分针网——每日分享:在Mongoose中使用嵌套的populate处理数据

更多文章:www.f-z.cn
 
文档一:
 
假设有以下mongodb的schema定义:
drawApply = new Schema({
salesId : { type: Schema.ObjectId, ref: 'sales' },
money : Number,
status : { type: Number, default: 0 },
createTime : { type: Date, default: Date.now }
});
 
sales = new Schema({
name : { type: String, required: true, unique: true },
pwd : String,
phone : String,
merchant : { type: Schema.ObjectId, ref: 'merchant' },
status : { type: Number, default: 0 }
});
 
merchant = new Schema({
name : String,
sname : String,
type : String
});
 
  表drawApply的salesId属性指定表sales的_id,表sales的属性merchant指定表merchant的_id。这是一种嵌套级联的关系。
 
  查找drawApply表的数据,并同时返回对应的sales表的数据,能够使用下面的方法:
drawApply .find().populate('salesId', '_id name phone merchant').sort({createTime: -1}).exec(function(err, list) {
// list of drawApplies with salesIds populated
});
 
  返回的结果中除了drawApply表的数据外,还会包含salesId中_id,name,phone,merchant四个属性的值。可是merchant属性的值是以ObjectId的形式显示的,若是想知道对应的merchant其它属性的值,则须要使用到嵌套的populate。代码以下:
drawApply .find().populate({
path : 'salesId',
select : '_id name phone merchant',
model : 'sales',
populate : {
path : 'merchant',
select : '_id sname',
model : 'merchant'
}).sort({createTime: -1}).exec(function(err, list) {
// list of drawApplies with salesIds populated and merchant populated
});
 
  若是drawApply表中还存在其它ObjectId类型的字段,则能够在populate方法后面继续跟其它的populate,使用方法相同,如:
drawApply .find().populate({
path : 'salesId',
select : '_id name phone merchant',
model : 'sales',
populate : {
path : 'merchant',
select : '_id sname',
model : 'merchant'
})
.populate('approver', 'name')
.populate('operator', 'name')
.sort({createTime: -1}).exec(function(err, list) {
// list of drawApplies with salesIds populated and merchant populated
});
 
文档二
 
在使用 mongoose 时,想经过一个外键与另外一张表创建关联时,不知该如何简单快捷的实现,特意去查了一下,发现了 population 这个功能,在此简单记录下 mongoose 的 populate 使用。
 
环境
 
Node: v7.0.0
Bluebird: v3.4.6
Mongoose: v4.6.8
参考文档
 
ECMAScript 6 入门 —— Promise对象, 阮一峰
Mongoose 之 Population 使用, aikin
Mongoose API v4.7.2
使用方法
 
我以为参考文档里的那篇文章 Mongoose 之 Population 使用, aikin 写的很详细了,这里为方便看,我把它复制过来了,因此,使用方法部分基本出自上述文章.
 
语法
 
Query.populate(path, [select], [model], [match], [options])
参数 Option
 
path
 
类型:String或Object。
 
String类型的时, 指定要填充的关联字段,要填充多个关联字段能够以空格分隔。
Object类型的时,就是把 populate 的参数封装到一个对象里。固然也能够是个数组。下面的例子中将会实现。
 
select
 
类型:Object或String,可选,指定填充 document 中的哪些字段。
 
Object类型的时,格式如: {name: 1, _id: 0},为0表示不填充,为1时表示填充。
String类型的时,格式如: “name -_id”,用空格分隔字段,在字段名前加上-表示不填充。详细语法介绍 query-select
尝试中发现 select 默认会填充 _id。
 
model
 
类型:Model,可选,指定关联字段的 model,若是没有指定就会使用Schema的ref。
 
match
 
类型:Object,可选,指定附加的查询条件。
 
options
 
类型:Object,可选,指定附加的其余查询选项,如排序以及条数限制等等。
 
基本使用
 
数据模型
 
建立三个Schema和Model。
var mongoose = require('mongoose');
mongoose .Promise = require('bluebird');
mongoose .connect('mongodb://localhost/population');
 
var Schema = mongoose.Schema;
var userSchema = new Schema({
name : String,
age : Number,
posts : [{type: Schema.Types.ObjectId, ref: 'post'}],
comments : [{type: Schema.Types.ObjectId, ref: 'comment'}]
});
var User = mongoose.model('user', userSchema);
 
var postSchema = new Schema({
title : String,
content : String,
author : {type: Schema.Types.ObjectId, ref: 'user'},
comments : [{type: Schema.Types.ObjectId, ref: 'comment'}]
});
var Post = mongoose.model('post', postSchema);
 
var commentSchema = new Schema({
content : String,
author : {type: Schema.Types.ObjectId, ref: 'user'}
})
var Comment = mongoose.model('comment', commentSchema);
 
exports .User = User;
exports .Post = Post;
exports .Comment = Comment;
 
注: ref 对应的应该是在connection中注册过的model。
 
var User = mongoose.model('user', userSchema);
...
author : {type: Schema.Types.ObjectId, ref: 'user'}
// 这里的 ref: 'user' 是第一行的 mongoose.model('user', userSchema) 第一个参数。
 
插入数据
var User = require('./model').User;
var Post = require('./model').Post;
var Comment = require('./model').Comment;
 
var tom = new User({name: 'Tom', age: 19});
var test = new Post({title: 'test', content: 'wakaka'});
var walala = new Comment({content: 'walala'});
 
tom .save().then(function(user) {
test .author = user;
walala .author = user;
return Promise.all([test.save(), walala.save(), user]);
}).spread(function(post, comment, user) {
user .posts.push(post);
user .comments.push(comment);
post .comments.push(comment);
return Promise.all([user.save(), post.save()]);
}).spread(function() {
console .log('success');
}).catch(function(reason) {
console .log(reason);
});
 
mongodb 查询数据
> db.users.find().pretty()
{
"_id" : ObjectId("584a030733604a156a4f65ff"),
"name" : "Tom",
"age" : 19,
"comments" : [
ObjectId("584a030733604a156a4f6601")
],
"posts" : [
ObjectId("584a030733604a156a4f6600")
],
"__v" : 1
}
> db.posts.find().pretty()
{
"_id" : ObjectId("584a030733604a156a4f6600"),
"author" : ObjectId("584a030733604a156a4f65ff"),
"title" : "test",
"content" : "wakaka",
"comments" : [
ObjectId("584a030733604a156a4f6601")
],
"__v" : 1
}
> db.comments.find().pretty()
{
"_id" : ObjectId("584a030733604a156a4f6601"),
"author" : ObjectId("584a030733604a156a4f65ff"),
"content" : "walala",
"__v" : 0
}
 
populate
 
填充单个字段
 
假如,填充 Comment 中的 author。
 
代码
 
这里经过传入 Object 类型参数调用 populate。
Comment .findOne({'content': 'walala'}).populate({path:'author', select: 'name'})
.exec().then(function(user) {
console .log(user);
}).catch(function(reason) {
console .log(reason);
});
 
结果
{ _id: 584a030733604a156a4f6601,
author : { _id: 584a030733604a156a4f65ff, name: 'Tom' },
content : 'walala',
__v : 0 }
 
填充多个字段
 
假如,咱们要填充 Post 中的 author 和 comments,且填充 author 的 name 和 age,还有 comments 的 content; 不填充 author 和 comments 的 _id。
 
代码
 
如下两种写法效果是同样的。
// 如果用字符串填写,select 同时做用于两个字段,即 author 和 comments 都会填充 name age content,若该字段没有这些数据,则不填充。
Post .findOne({'title': 'test'}).populate('author comments', 'name age content -_id').exec()
.then(function(post) {
console .log(post);
}).catch(function(reason) {
console .log(reason);
});
 
// 数组形式能够单独对某一字段用 select 选择要填充的数据。
Post .findOne({'title': 'test'}).populate([{path: 'author', select: 'name age -_id'}, {path: 'comments', select: 'content -_id'}]).exec()
.then(function(post) {
console .log(post);
}).catch(function(reason) {
console .log(reason);
});
 
结果
{ _id: 584a030733604a156a4f6600,
author : { name: 'Tom', age: 19 },
title : 'test',
content : 'wakaka',
__v : 1,
comments : [ { content: 'walala' } ] }
 
以上全部,若有错误,麻烦指出,我会及时更改的。
 
有关populate的具体用法能够参考mongoose的官方文档http://mongoosejs.com/docs/populate.html#deep-populate
 
 
 
加入职业技能圈 q群:272292492
相关文章
相关标签/搜索