如何填充作为另一个文档的数组元素的子文档的字段?
Posted
技术标签:
【中文标题】如何填充作为另一个文档的数组元素的子文档的字段?【英文标题】:How to populate a field of a subdocument which is an array element of another document? 【发布时间】:2020-03-07 12:15:36 【问题描述】: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();
这看起来不像是这样做的预期方式。是否可以在不迭代查找索引的情况下做到这一点?最好只执行一次查询。
【问题讨论】:
如果您能提供一些示例文件和预期结果就很容易了!! @srinivasy 我添加了更多细节,但我不确定你的意思,因为我无法提供关于我的问题的其他信息。 您必须使用 mongoose 还是可以使用 mongoDB 的原生功能 $lookup 来完成(或多或少两者应该类似)? 【参考方案1】:假设您的数据是这样的:
一些集合:
/* 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"
Mongoose 架构:
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
从其他集合中获取相应的文档。
【讨论】:
很好的答案。那个投影语法'works.$': 1
正是我所缺少的。澄清一下,$
符号表示与查询匹配的元素对吗?
@AnthonyYershov :是的,它是(docs.mongodb.com/manual/reference/operator/update/…),但我认为它有一个缺点 - 只有当你的数组有重复的值时,它可能只返回第一个找到的匹配值,但在你的情况下应该不是问题,因为我希望您不会在works数组中有任何重复!无论如何,只要把 ref 放在这里,因为值得了解它。..以上是关于如何填充作为另一个文档的数组元素的子文档的字段?的主要内容,如果未能解决你的问题,请参考以下文章
在 MongoDB 中,何时使用简单的子文档,何时使用具有 2 字段元素的数组?
Mongoose - 无法在路径 notification.from 上使用排序填充,因为它是文档数组的子属性