Mongoose 使用之 Population

跟風遠走 提交于 2020-04-06 22:34:05

何为 Population

用过 MongoDB 的人应该都知道它是没有关系型数据库里的 join 特性的,这意味着当我们使用 MongoDB 读取某个 document 及其关联的 document 的字段的时候,变得尤为麻烦。

基于此,Mongoose 封装了一个 population 的功能,当你在定义 Schema 的时候指定了某个 field 是引用了另一个 Schema ,那么你在获取 document 的时候就可以使用 populate 方法让 Mongoose 帮你通过引用 Schema 和 id 找到关联的另一个 document,并且用该 document 的内容替换掉原来引用字段的内容,使引用的 ducoment 使用起来就像是内嵌的 document 一样方便。

定义带有引用字段的 Schema

首先,如果要使用这个功能,必须给你的“外键字段”定义 Mongoose 的“外键约束”(这里借用关系型数据库的术语,只是为了帮助理解)。假设我们有一个用户的 Schema ,其中有一个字段是followings,保存用户关注了的其他用户,类似微博。Mongoose 的 Schema 定义如下:

var mongoose = require('mongoose')
  , Schema = mongoose.Schema
  
var UserSchema = Schema({
  name    : String,
  followings : [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
    
var User = mongoose.model('User', UserSchema);

保存引用字段

然后我们创建两个 User 实例,并且先将其中之一保存进数据库(为了产生 _id ):

var lily = new User({name: 'lily'})
   ,lucy = new User({name: 'lucy'});
lily.save(cb);

lily 保存成功后,我们再在回调函数 cb 中保存 lucy ,不过这个时候假设 lucy 关注了 lily:

function cb(err) {
    if(err) throw err;
    lucy.followings.push(lily._id);// line 1
    lucy.save(cb1);
}

这样就保存完成了。不过好像我们没用引用字段之前也是这么保存的吧?有没有更直接一点的?有,你其实可以将 line 1 的语句改成以下形式, Mongoose 也会自动帮你做内部解析的:

lucy.followings.push(lily);

这样看起来代码就更接近自然语言了,有点ORM的味道。

查询 document

当然,上面的例子可能对开发者来说没有什么太大的用处,那么就来看看 population 在获取 document 的时候能给我们带来什么好处吧。

假设我们现在要找到 lucy 的信息以及她所关注的用户,我们可以这样:

User.findOne({name: 'lucy'}).exec(cb2);

但是这样拿出来的 lucy 的 followings 是一组存储了 ObjectId 的数组,还得去一个个查找对应的用户,多麻烦啊。所以这个时候用 population 就简单多了,直接指定你想要 populate 哪个引用字段:

User.findOne({name: 'lucy'}).populate('followings').exec(cb2);

这样的话,在回调函数 cb2 中你得到的就是一个存储了若干个 User 对象的数组了。

populate 方法

populate 方法可以用在 document 上、 model 上或者是 query 对象上,这意味着你几乎可以在任何地方调用这个方法以填充你的引用字段。

当然,populate 方法在不同对象上参数不大一样,但是都接收一个option的参数,你可以用这些参数指定:

  • path: 以空格分隔的引用字段的名称
  • select: 填充引用 document 中的哪些字段
  • match: 可选,指定附加的查询条件
  • model: 可选,指定引用的 model
  • options: 可选,指定附加的其他查询选项,如排序以及条数限制等等

引用字段的类型

目前,Mongoose 只支持以下几种引用字段的类型:

  • ObjectId
  • Number
  • String
  • Buffer

而且自然而然,引用 document 的主键类型必须和引用字段类型相对应。在生产环境中,推荐主键类型和引用类型都使用 ObjectId ,一是因为 ObjectId 不包含业务含义,二是 ObjectId 不大可能重复,三是因为 Mongoose 默认生成的主键类型就是 ObjectId ,可以减少很多配置的操作。

更多信息请关注这里

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!