简单的创建声明三张表: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'}
})
查询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后放入的字段名,这个是自定义的,是个数组类型。
}
}
]);