输入样本数据
/* 1 */
{ "name" : "alice",
"attibutes" : [
{ "key" : "marks", "value" : 10 },
{ "key" : "age", "value" : 10 }
]
}
/* 2 */
{ "name" : "bob",
"attibutes" : [ { "key" : "marks", "value" : 20 } ]
}
/* 3 */
{ "name" : "charlie",
"attibutes" : [ { "key" : "age", "value" : 20 } ]
}
/* 4 */
{ "name" : "dan",
"attibutes" : []
}
/* 5 */
{ "name" : "el",
"attibutes" : [
{ "key" : "marks", "value" : 5},
{ "key" : "age", "value" : 5}
]
}
我的用例是我需要标记上的文档过滤和年龄上的排序。并非我的所有文档都具有必要的数据。 我希望输出中没有没有标记的文档,但是即使文档没有使用期限,也希望该文档出现在输出中。
查询1:仅过滤标记,按预期方式工作,返回两个文档
db.getCollection('students').aggregate([
{
$match: {
attributes: {
$elemMatch: {
value: {$gte:10},
key:"marks"
}
}
}
}
])
返回与Alice和Bob对应的文档。 预期
现在添加排序,这是我通过展开来完成的,查询看起来像
db.getCollection('students').aggregate([
{
$match:{
attributes:{
$elemMatch:{
value:{
$gte:10
},
key:"marks"
}
}
}
},
{ $addFields:{ attributes_unwind:"$attributes" } },
{ $unwind:"$attributes_unwind" }, //UNWIND OPERATION
{ $match:{ "attributes_unwind.key":"age" } },
{ $sort:{ "attributes_unwind.value":1 } },
{ $project:{ "attributes_unwind":false } }
])
由于展开+匹配+排序,此查询删除了与bob对应的文档,该文档没有 age 条目。
我想通过在标记// UNWIND OPERATION的行之前添加age的键值(sort属性)来绕过此问题。仅当原始列表没有年龄密钥时,才应有条件地插入此内容。
到目前为止,我是
db.getCollection('students').aggregate([
{
$match: {
attributes: {
$elemMatch: {
value: {$gte:10},
key:"marks"
}
}
}
},
{ $addFields: { attributes_unwind: "$attributes" } },
{ $addFields:
{ attributes_unwind:
{ $cond :
[
{
attributes_unwind :{ $elemMatch:{key:"age"}}
},
"$attributes_unwind",
{ $concatArrays: [ "$attributes_unwind", [ {"key":"age","value":""}] ] }
]
}
}
},
{ $unwind: "$attributes_unwind" },
{ $match: {"attributes_unwind.key": "age"}},
{ $sort: {"attributes_unwind.value": 1}},
{ $project: {"attributes_unwind": false}}
])
但是如果出现错误
Error: command failed: {
"ok" : 0,
"errmsg" : "Unrecognized expression '$elemMatch'",
"code" : 168,
"codeName" : "InvalidPipelineOperator"
} : aggregate failed
答案 0 :(得分:1)
我通过过滤器->尺寸-> gt-> cond解决了这个问题。在此处共享解决方案。我愿意提出更好的查询意见
5693
5701
5747
5747
5747
5812
5822
5822