在mongodb集合中,我有以下文档:
{"id":"1234","name":"John","stateCode":"CA"}
{"id":"1234","name":"Smith","stateCode":"CA"}
{"id":"1234","name":"Tony","stateCode":"GA"}
{"id":"3323", "name":"Neo","stateCode":"OH"}
{"id":"3323", "name":"Sam","stateCode":"US"}
{"id":"4343","name":"Bruce","stateCode":"NV"}
我正在尝试编写一个mongo聚合查询,该查询执行以下操作:
基于id
字段的匹配
赋予stateCode
字段中具有“ NV”或“ GA”以外的值的文档优先级。
如果所有文档的值均为“ NV”或“ GA”,则忽略优先级。
如果任何文档中的{NV}或“ GA”以外的还有stateCode
,则返回这些文档。
示例1:
id = "1234"
then return
{"id":"1234","name":"John","stateCode":"CA"}
{"id":"1234","name":"Smith","stateCode":"CA"}
示例2:
id = "4343"
then return
{"id":"4343","name":"Bruce","stateCode":"NV"}
请帮助查询以实现此目标。
我尝试执行查询,但遇到错误:
Failed to execute script.
Error: command failed: {
"ok" : 0,
"errmsg" : "input to $filter must be an array not string",
"code" : 28651,
"codeName" : "Location28651"
} : aggregate failed
查询:
db.getCollection('emp').aggregate([{$match:{
'id': "1234"
}
},
{
$project: {
"data": {
$filter: {
input: "$stateCode",
as: "data",
cond: { $ne: [ "$data", "GA" ],$ne: [ "$data", "NV" ] }
}
}
}
}
])
答案 0 :(得分:2)
我实际上建议您将其分为2个查询,首先尝试查找状态码不同的文档,如果失败,则检索其余文档。
这是一个可以一次性完成的工作流水线,由于我们无法事先知道条件是否成立,因此我们需要迭代所有与id
匹配的文档,在许多文档共享id
的情况下,这一事实非常低效,如果不可能,那么使用此管道就可以了。
db.getCollection('emp').aggregate([
{
$match: {
'id': "1234"
}
},
{ //we have to group so we can check
$group: {
_id: null,
docs: {$push: "$$ROOT"}
}
},
{
$addFields: {
highPriorityDocs: {
$filter: {
input: "$docs",
as: "doc",
cond: {$and: [{$ne: ["$$doc.stateCode", "NV"]}, {$ne: ["$$doc.stateCode", "GA"]}]}
}
}
}
},
{
$project: {
finalDocs: {
$cond: [ // if size of high priority docs gt 0 return them.
{$gt: [{$ize: "$highPriorityDocs"}, 0]},
"$highPriorityDocs",
"$docs"
]
}
}
},
{
$unwind: "$finalDocs"
},
{
$replaceRoot: {newRoot: "$finalDocs"}
}
])
最后两个阶段只是恢复原始结构,如果您不关心它,可以将其删除。