简单的创建声明三张表:user/department/project
const UserSchema = new mongoose.Schema({
username: { type: String, required: true },
password: { type: String, required: true },
department: { type: mongoose.Schema.Types.ObjectId, ref: 'Department'}
project: { type: mongoose.Schema.Types.ObjectId, ref: 'Project'}
})
const DepartmentSchema = new mongoose.Schema({
name: { type: String, required: true },
project: { type: mongoose.Schema.Types.ObjectId, ref: 'Project'}
})
const ProjectSchema = new mongoose.Schema({
name: { type: String, required: true },
owner: { type: mongoose.Schema.Types.ObjectId, ref: 'User'}
})
请忽略开发语言0_0…
- 查询user表,以及关联查询project和department。深度为1的多个关联查询用数组,单个用字符串即可。
model.User.find().populate(['department','project'])
- 查询user表,关联查询project并且再查询owner字段,即深度为2的关联查询。
model.User.find().populate({ path: 'project', populate: { path: 'owner' } })
- 在2的基础上查询owner的时候只想要name字段,而password不返回。
model.User.find().populate({ path: 'project', populate: { path: 'owner', select: 'name' } })
- 1和2结合一起,即需要关联查询project和department,且project中再关联查询owner字段
const pop = [
{
path: 'department'
},
{
path: 'project',
populate: { path: 'owner' }
},
];
model.User.find().populate(pop);
另外有几点需要注意:
- 如果关联的字段是数组的话,跟上面用法是一样的。
- 如果关联字段查询不到的话,比如上面
user.project = null
,如果是数组字段则为空数组。 - 关联的字段类型可以是
ObjectId, Number, String, and Buffer
,但是官方文档上说:However, you should use ObjectId unless you are an advanced user and have a good reason for doing so.
下面说一下跟$lookup的关系
- user表中查到department可以用
populate
,也可以用$lookup
。但如果想在department表中查到user则只能用$lookup
。也就是说正向关联的话两者都能用,反向的话只能用$lookup
(但个人觉得正向的话还都是用populate
,因为$lookup
写法较麻烦)。 populate
用的是refs查询,在性能上$lookup
比较有优势,比如查询user表一次出来10条记录,再用refs查询project需要10次,而$lookup
只需要1次。当然查询次数固然会影响整个查询过程消耗的时间,但相比在网络中传输数据所耗费的时间还是可以接受的。- 简单给出
$lookup
的用法。
在department中查询到该部门下所有的user在department中查询到该部门下所有的user在department中查询到该部门下所有的user在department中查询到该部门下所有的user
model.Department.aggregate([
{
$lookup: {
from: 'users', // 从哪个Schema中查询(一般需要复数,除非声明Schema的时候专门有处理)
localField: '_id', // 本地关联的字段
foreignField: 'department', // user中用的关联字段
as: 'users' // 查询到所有user后放入的字段名,这个是自定义的,是个数组类型。
}
}
]);
更加详细的内容参考populate的官方文档