Mongoose 是 MongoDB 的 ODM(Object Document Mapper)。
什么是ODM? 其实和ORM(Object Relational Mapper)是同类型的工具。都是将数据库的数据转化为代码对象的库,使用转化后的对象可以直接对数据库的数据进行CRUD(增删改查)。
MongoDB 是文档型数据库(Document Database),不是关系型数据库(RelationalDatabase)。而Mongoose可以将 MongonDB 数据库存储的文档(documents)转化为 javascript对象,然后可以直接进行数据的增删改查。
因为MongoDB是文档型数据库,所以它没有关系型数据库joins(数据库的两张表通过”外键”,建立连接关系。) 特性。也就是在建立数据的关联时会比较麻烦。为了解决这个问题,Mongoose封装了一个Population
功能。使用Population
可以实现在一个 document 中填充其他 collection(s)
的 document(s)
。
在定义Schema的时候,如果设置某个 field 关联另一个Schema,那么在获取 document 的时候就可以使用 Population 功能通过关联Schema的 field 找到关联的另一个 document,并且用被关联 document 的内容替换掉原来关联字段(field)的内容。
接下来分享下:Query#populate Model#populate Document#populate的用法
先建立三个Schema
和Model
:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name : { type: String, unique: true },
posts : [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});
var User = mongoose.model('User', UserSchema);
var PostSchema = new Schema({
poster : { type: Schema.Types.ObjectId, ref: 'User' },
comments : [{ type: Schema.Types.ObjectId, ref: 'Comment' }],
title : String,
content : String
});
var Post = mongoose.model('Post', PostSchema);
var CommentSchema = new Schema({
post : { type: Schema.Types.ObjectId, ref: "Post" },
commenter : { type: Schema.Types.ObjectId, ref: 'User' },
content : String
});
var Comment = mongoose.model('Comment', CommentSchema);
在上述的例子中,创建了三个 Models:User
,Post
,Comment
。User
的属性 post`,对应是一个 ObjectId 的数组。ref表示关联Post(注意: 被关联的model的 type 必须是ObjectId, Number, String, 和 Buffer 才有效)。Post
的属性 poster 和 comments 分别关联User和Comment。Comment
的属性 post 和 commenter 分别关联Post和User。
三个 Models 的关系:一个 user–has many–>post。一个 post–has one
–>user,has many–>comment。一个 comment–has one–>post 和 user。
创建一些数据到数据库:
// 连接数据库
mongoose.connect('mongodb://localhost/population-test', function (err){
if (err) throw err;
createData();
});
function createData() {
var userIds = [new ObjectId, new ObjectId, new ObjectId];
var postIds = [new ObjectId, new ObjectId, new ObjectId];
var commentIds = [new ObjectId, new ObjectId, new ObjectId];
var users = [];
var posts = [];
var comments = [];
users.push({
_id : userIds[0],
name : 'aikin',
posts : [postIds[0]]
});
users.push({
_id : userIds[1],
name : 'luna',
posts : [postIds[1]]
});
users.push({
_id : userIds[2],
name : 'luajin',
posts : [postIds[2]]
});
posts.push({
_id : postIds[0],
title : 'post-by-aikin',
poster : userIds[0],
comments : [commentIds[0]]
});
posts.push({
_id : postIds[1],
title : 'post-by-luna',
poster : userIds[1],
comments : [commentIds[1]]
});
posts.push({
_id : postIds[2],
title : 'post-by-luajin',
poster : userIds[2],
comments : [commentIds[2]]
});
comments.push({
_id : commentIds[0],
content : 'comment-by-luna',
commenter : userIds[1],
post : postIds[0]
});
comments.push({
_id : commentIds[1],
content : 'comment-by-luajin',
commenter : userIds[2],
post : postIds[1]
});
comments.push({
_id : commentIds[2],
content : 'comment-by-aikin',
commenter : userIds[1],
post : postIds[2]
});
User.create(users, function(err, docs) {
Post.create(posts, function(err, docs) {
Comment.create(comments, function(err, docs) {
});
});
});
}
数据的准备就绪后,接下来就是探索populate方法:
Query#populate
什么Query? Query(查询),可以快速和简单的从MongooDB查找出相应的 document(s)。 Mongoose封装了很多查询的方法,使得对数据库的操作变得简单啦。这里分享一下populate方法用法。
语法:
Query.populate(path, [select], [model], [match], [options])
参数:
path
类型:String
或Object
。
String
类型的时, 指定要填充的关联字段,要填充多个关联字段可以以空格分隔。
Object
类型的时,就是把populate
的参数封装到一个对象里。当然也可以是个数组。下面的例子中将会实现。
select
类型:Object
或String
,可选,指定填充document
中的哪些字段。
Object
类型的时,格式如:{name: 1, _id: 0}
,为0表示不填充,为1时表示填充。
String
类型的时,格式如:"name -_id"
,用空格分隔字段,在字段名前加上-表示不填充。详细语法介绍query-select
model
类型:Model
,可选,指定关联字段的model
,如果没有指定就会使用Schema的ref。match
类型:Object
,可选,指定附加的查询条件。options
类型:Object
,可选,指定附加的其他查询选项,如排序以及条数限制等等。
填充User
的posts
字段:
User.findOne({name: 'aikin'})
.exec(function(err, doc) {
var opts = [{
path : 'posts',
select : 'title'
}];
doc.populate(opts, function(err, populatedDoc) {
console.log(populatedDoc.posts[0].title); // post-by-aikin
});
});