我想从嵌套数组中选择第一项,而不是获取整个文档。
假设我有一个类似的架构:
const parentSchema = mongoose.Schema({
name: String,
children: []
});
const grandparentSchema = mongoose.Schema({
name: String,
children: [parentSchema]
})
将转换为此示例实例:
{
name: 'Grandparent Foo',
children: [
{
name: 'Parent Foo',
children: ['Child Foo', 'Child Bar', 'Child Baz']
}
]
}
我想得到'Parent Foo'
的第一个孩子,所以要把它煮熟,我应该回来'Child Foo
'
正如您所看到的,孙子是普通的String
,而不是Document
s(与父母相比),所以我不能用点符号选择它们。
我不想返回整个文档并在代码中过滤掉它。由于孙子数组(children
'Parent Foo'
数组$pop
)可能包含数百万条目,所以我只想接通第一个孙子。
我需要这个,因为我想$pop
第一个孙子并将其归还。为此,我计划首先获取该项目,然后{{1}}关闭它,因此我问这个问题
答案 0 :(得分:1)
如果不在数据库中投入额外的工作,你就不能真的。
作为一般性解释:
Grandparent.find(
{ "children.name": "Parent Foo" },
{ "children.$": 1 }
)
将仅返回"children"
中匹配的条目,而不存在其他条目。
如果您明确需要"首先"数组元素,然后使用.aggregate()
:
Granparent.aggregate([
{ "$match": { "children.name": "Parent Foo" } },
{ "$addFields": {
"children": {
"$map": {
"input": {
"$filter": {
"input": "$children",
"as": "child",
"cond": { "$eq": [ "$$child.name", "Parent Foo" ] }
}
},
"as": "child",
"in": {
"name": "$$child.name",
"children": { "$arrayElemAt": [ "$$child.children", 0 ] }
}
}
}
}}
])
所以你基本上使用$filter
来复制标准的位置匹配,然后使用$map
重塑$arrayElemAt
或$slice
以实际获得内部的第一个元素阵列。
相比之下,如果你生活在返回"少量的额外数据",那么你只需切断位置匹配:
Grandparent.find(
{ "children.name": "Parent Foo" },
{ "children.$": 1 }
).lean().exec((err,docs) => {
docs = docs.map( doc => {
doc.children = doc.children.map( c => c.children = c.children.slice(0,1) );
return doc;
});
// do something with docs
所以我们在光标中返回了一点,只需要很少的努力就可以摆脱那些非常小的数据。
由于实际数据的实际大小,里程可能因此而异,但如果差异为“小”,则通常最好“修剪”#34;在客户端而不是服务器。