如何填充作为另一个文档的数组元素的子文档的字段?
How to populate a field of a subdocument which is an array element of another document?
let collection = await Collection.findOne({ 'works._id': req.params.id }).populate('works.0.photo');
此代码将填充索引 0 中的 work
子文档,但是我希望它填充对应于 req.params.id
.
的索引
我想要类似 .populate('works.i.photo')
的东西,其中 i
代表作品的索引,其中包含匹配 req.params.id
.
的 _id
我知道怎么做了,但我确信有更好的方法。
let collection = await Collection.findOne({ 'works._id': req.params.id });
const idx = collection.works.findIndex(work => work._id == req.params.id);
collection = await collection.populate(`works.${idx}.photo`).execPopulate();
这看起来不像是这样做的预期方式。是否可以在不迭代查找索引的情况下做到这一点?最好只执行一次查询。
假设您的数据是这样的:
一些集合:
/* 1 */
{
"_id" : ObjectId("5dc9c61959f03a3d68cfb8d3"),
"works" : []
}
/* 2 */
{
"_id" : ObjectId("5dc9c72e59f03a3d68cfd009"),
"works" : [
{
"_id" : 123,
"photoId" : ObjectId("5dc9c6ae59f03a3d68cfc584")
},
{
"_id" : 456,
"photoId" : ObjectId("5dc9c6b659f03a3d68cfc636")
}
]
}
图片集:
/* 1 */
{
"_id" : ObjectId("5dc9c6ae59f03a3d68cfc584"),
"photo" : "yes"
}
/* 2 */
{
"_id" : ObjectId("5dc9c6b659f03a3d68cfc636"),
"photo" : "no"
}
/* 3 */
{
"_id" : ObjectId("5dc9c6c259f03a3d68cfc714"),
"photo" : "yesno"
}
猫鼬模式:
const photoSchema = new Schema({
_id: Schema.Types.ObjectId,
photo: String,
});
const someColSchema = new Schema({
_id: { type: Schema.Types.ObjectId },
works: [{ _id: { type: Number }, photoId: { type: Schema.Types.ObjectId, ref: 'photo' } }]
});
const someCol = mongoose.model('someCollection', someColSchema, 'someCollection');
const photoCol = mongoose.model('photo', photoSchema, 'photo');
代码:
1) 使用 Mongoose 填充 (Mongoose Populate) :
let values = someCol.find({"works._id": 123}, {_id: 0, 'works.$': 1}).populate('works.photoId').lean(true).exec();
2) 使用 mongoDB 的原生 $lookup (mongoDB $lookup) :
someCol.aggregate([{ $match: { 'works._id': 123 } }, { $unwind: '$works' }, { $match: { 'works._id': 123 } }, {
$lookup:
{
from: "photo",
localField: "works.photoId",
foreignField: "_id",
as: "doc"
}
}, { $project: { _id: 0, doc: { $arrayElemAt: ["$doc", 0] } } }])
两者的工作方式应该相似,在聚合中我们正在做 $match
来过滤给定的条件,$unwind
来解包作品数组,再次做一个过滤器,只保留数组中符合过滤条件的值& 然后做 $lookup
从其他集合中获取相应的文档。
let collection = await Collection.findOne({ 'works._id': req.params.id }).populate('works.0.photo');
此代码将填充索引 0 中的 work
子文档,但是我希望它填充对应于 req.params.id
.
我想要类似 .populate('works.i.photo')
的东西,其中 i
代表作品的索引,其中包含匹配 req.params.id
.
_id
我知道怎么做了,但我确信有更好的方法。
let collection = await Collection.findOne({ 'works._id': req.params.id });
const idx = collection.works.findIndex(work => work._id == req.params.id);
collection = await collection.populate(`works.${idx}.photo`).execPopulate();
这看起来不像是这样做的预期方式。是否可以在不迭代查找索引的情况下做到这一点?最好只执行一次查询。
假设您的数据是这样的:
一些集合:
/* 1 */
{
"_id" : ObjectId("5dc9c61959f03a3d68cfb8d3"),
"works" : []
}
/* 2 */
{
"_id" : ObjectId("5dc9c72e59f03a3d68cfd009"),
"works" : [
{
"_id" : 123,
"photoId" : ObjectId("5dc9c6ae59f03a3d68cfc584")
},
{
"_id" : 456,
"photoId" : ObjectId("5dc9c6b659f03a3d68cfc636")
}
]
}
图片集:
/* 1 */
{
"_id" : ObjectId("5dc9c6ae59f03a3d68cfc584"),
"photo" : "yes"
}
/* 2 */
{
"_id" : ObjectId("5dc9c6b659f03a3d68cfc636"),
"photo" : "no"
}
/* 3 */
{
"_id" : ObjectId("5dc9c6c259f03a3d68cfc714"),
"photo" : "yesno"
}
猫鼬模式:
const photoSchema = new Schema({
_id: Schema.Types.ObjectId,
photo: String,
});
const someColSchema = new Schema({
_id: { type: Schema.Types.ObjectId },
works: [{ _id: { type: Number }, photoId: { type: Schema.Types.ObjectId, ref: 'photo' } }]
});
const someCol = mongoose.model('someCollection', someColSchema, 'someCollection');
const photoCol = mongoose.model('photo', photoSchema, 'photo');
代码:
1) 使用 Mongoose 填充 (Mongoose Populate) :
let values = someCol.find({"works._id": 123}, {_id: 0, 'works.$': 1}).populate('works.photoId').lean(true).exec();
2) 使用 mongoDB 的原生 $lookup (mongoDB $lookup) :
someCol.aggregate([{ $match: { 'works._id': 123 } }, { $unwind: '$works' }, { $match: { 'works._id': 123 } }, {
$lookup:
{
from: "photo",
localField: "works.photoId",
foreignField: "_id",
as: "doc"
}
}, { $project: { _id: 0, doc: { $arrayElemAt: ["$doc", 0] } } }])
两者的工作方式应该相似,在聚合中我们正在做 $match
来过滤给定的条件,$unwind
来解包作品数组,再次做一个过滤器,只保留数组中符合过滤条件的值& 然后做 $lookup
从其他集合中获取相应的文档。