我对MongoDB中的集合有以下结构
{
'_id': 45
'tags': [ 'tag 1', 'tag 3' ]
'active': true
'fields': [
{ 'name': 'common field 1', 'type': 'text', 'value': 'some text', ... },
{ 'name': 'common field 2', ... },
{ 'name': 'multivalued field 1',
'type': 'multifield',
'valueCount': 5,
'value': [
{ 'name': 'subfield1', ..., 'value': [1, 2, 3, 4, 5]},
{ 'name': 'subfield2', ..., 'value': ["one", "two", "three", "four", "five"]},
{ 'name': 'subfield3', ..., 'value': ["here", "there", "", "", ""]}
], ... }
]
}
我正在尝试在我的API中实现投影:例如,如果用户请求
api/collection/?fields=id,fields{common field 2, multifield{subfield1}}
结果应为
{
'_id': 45
'fields': [
{ 'name': 'common field 1', 'type': 'text', 'value': 'some text', ... },
{ 'name': 'multivalued field 1',
'type': 'multifield',
'valueCount': 5,
'value': [
{ 'name': 'subfield1', ..., 'value': [1, 2, 3, 4, 5]},
], ... }
]
}
由于'字段'名称不是实际键,我不能使用mongo投影,比如说
db.collection.find({},{_id: 1, tags: 1, fields.'common field 1': 1})
所以我必须在数组中搜索“name”属性与我的投影参数匹配的字段。我在第一级数组中实现了聚合和$ redact,如本回答https://stackoverflow.com/a/24032549/5418731
所示db.points.aggregate([
{ $match: {}},
{
$project: {_id :1, fields: 1}
},
{ $redact : {
$cond: {
if: { $or : [{ $not : "$name" }, { $eq: ["$name", "common field 1"] }]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}])
但是,我无法使用$ redact从多值字段中的内部数组中选择子字段。 $或参数必须类似于
[{ $not : "$name" }, { $eq: ["$name", "common field 1"] }, { $eq: ["$name", "subfield1"] }]
表示与指定子字段名称相同的第一级字段也将通过。
将MongoDB升级到3.2之后,我在这个答案https://stackoverflow.com/a/12241930/5418731中尝试了$ filter解决方案,这对第一级数组也适用:
db.points.aggregate([
{$project: {
fields: {$filter: {
input: '$fields',
as: 'field',
cond: {$eq: ['$$field.name', 'multivalued field 1']}
}}
}}
])
但我找不到一种方法来“嵌套”使用它并过滤第二级数组项。添加{$eq: ['$$field.value.name', 'subfield1']}
不起作用。
最后,我尝试了这里提供的$ map解决方案https://stackoverflow.com/a/24156418/5418731:
db.points.aggregate([
{ "$project": {
"_id": 1,
"fields": {
"$map": {
"input": "$fields",
"as": "f",
"in": {
"$ifNull": [
{
"name": "$multivalued field 1",
"type": "$multifield", //attempt to restrict search to fields with arrays as values
"value": {
"$map": {
"input": "$$f.value",
"as": "v",
"in": {
"$ifNull": [
{ "name": "$subfield1"},
false
]
}
}
}
},
false
]
}
}
}
}}
])
但是这个不起作用,因为每个“fields”项的“value”属性不一定是数组,当它不是整个查询失败时。
我即将放弃并掩盖JS中的结果。有没有一个很好的解决方案与Mongo?
答案 0 :(得分:0)
您的样本请求中是否存在拼写错误。当您查询文档时 名称为"普通字段2"但是你期待"共同领域1"在你的回复中。
此外,您只需使用聚合管道并按以下方式继续操作,而不是使其如此复杂:
这样的事情:
db.points.aggregate([
{ $unwind: "$fields" },
{ $match: { "fields.name": "common field 1", "fields.type": "multifield" } },
{ $unwind: "$fields.value" },
{ $match: { "fields.value.name": "subfield1" } }
]);