mongoose的Population问题
发布于 10 年前 作者 udbmnm 5567 次浏览 最后一次编辑是 8 年前

Population应该尽量少用吗?我在nodeclub的models中没看到使用ref来做关联,那读取数据的时候怎么做到一次查询

7 回复

如果是多表查询的话是不行的,具体要在程序里面实现。 Population貌似必须2个表之间有_id关联,可是很多情况貌似满足不了需求。 所以要么在存表的时候给一定的冗余,要么所有的关联在代码中实现(注意一下效率,避免内存溢出)

个人理解,不对勿喷

个人感觉是mongo数据库的集合设计问题 - 内嵌文档 vs. DBRef。如果有两个实体,比如User和Team,约束为M:1(一个Team下可以包含多个User,一个User只能属于一个Team),这种情况下,可以设计为DBRef,集合中数据可能为: User:

{ "_id" : ObjectId("id_of_user#1"), "teamId" : [ { "$ref" : "Team", "$id" : ObjectId("id_of_team#1") } ]}
{ "_id" : ObjectId("id_of_user#2"), "teamId" : [ { "$ref" : "Team", "$id" : ObjectId("id_of_team#1") } ]} 

Team:

{ "_id" : ObjectId("id_of_team#1") } 

在mongoose中,要定义上述关系,可以这样来定义Schema:

var User = new Schema({
	team: { type: Schema.Types.ObjectId, ref: 'Team' }, 
});

当然还需要导出Schema为Model (mongoose.model(‘User’, User);)。定义Team:

var Team = new Schema({
	team: { type: Schema.Types.ObjectId, ref: 'Team' },
});

从数据库里查询User时可以一并查出Team对象:

User.findOne('id_of_some_user')
       .populate('team')
       .exec(function (err, user) {
                 // ...
       });

这样,user.team就不会是一个ObjectId对象。需要说明的是: 1). 查看数据库会发现,mongoose弄出来的数据和mongodb的官方做法不一样,比如它不是

 { "_id" : ObjectId("id_of_user#1"), "teamId" : [ { "$ref" : "Team", "$id" : ObjectId("id_of_team#1") } ]}
而是
{ "_id" : ObjectId("id_of_user#1"), "teamId" : ObjectId("id_of_team#1")  }

这是因为通过Schema的定义,数据的关联关系已经表达得很清楚了。当然,这也可能成为你考虑是否使用mongoose的一个因素(数据活得比应用久,说不定你要考虑换框架呢)。

2). populate会向mongodb数据库发起新的数据库查询,即额外的查询请求(mongodb中并没有关系型数据库的表JOIN操作)。

@GuoZhang 谢谢回复 这样写 var User = new Schema({ team: [{ type: Schema.Types.ObjectId, ref: 'Team' }], }); 生成的就是 { "_id" : ObjectId("id_of_user#1"), "teamId" : [ { "$ref" : "Team", "$id" : ObjectId("id_of_team#1") } ]} 这样的 既然. populate会向mongodb数据库发起新的数据库查询 ,那应该直接尽量自己写程序解决,populate只是简化了我们查询

不用populate 自己又如何写呢?难道拿到id再查询一次数据库,那结果不是还一样,如果是查询很多数据,要全部遍历一次分别拿id去查一下吗?我只是想知道大家不用populate 怎么处理的 还有populate 这个好像只能查询直接关联的model,关联的model的关联model就不能查询出来了,怎么办呢?

@hanzel21cn 你说的所在的关联在代码中实现是如何做的?可以做到多级关联查询吗?

@GuoZhang 知道如何实现多级关联查询吗?

找到了,最新版的mongoose支持了deep-populate 官方文档: deep-populate

回到顶部