在我的MongoDB人员集合中,我需要过滤具有相同“别名”属性值的人员,保留其中第一个,并为所有人员保留空的“别名”。
数据是这样的:
{ "_id" : "1", "flag" : true, "name" : "Alice", "alias" : null, "dateOfBirth": new ISODate('1995-12-27T00:00:00.000Z') },
{ "_id" : "2", "flag" : true, "name" : "Bob", "alias" : "4c", "dateOfBirth": new ISODate('1996-12-27T00:00:00.000Z') },
{ "_id" : "3", "flag" : true, "name" : "Bobby", "alias" : "4c", "dateOfBirth": new ISODate('1997-12-27T00:00:00.000Z') },
{ "_id" : "4", "flag" : true, "name" : "Cristina", "alias" : null, "dateOfBirth": new ISODate('1998-12-27T00:00:00.000Z') },
{ "_id" : "5", "flag" : false, "name" : "Diego", "alias" : null, "dateOfBirth": new ISODate('1999-12-27T00:00:00.000Z') },
{ "_id" : "6", "flag" : true, "name" : "Zoe", "alias" : "22", "dateOfBirth": new ISODate('2000-12-27T00:00:00.000Z') }
这是我的查询:
db.people.aggregate([
{ '$match': { 'flag': true } },
{ '$project': {
'name': 1,
'alias': {
'$cond': [
{ '$eq': [ '$alias', null ] },
'$_id',
'$alias'
]
}
}},
{ '$group': {
'_id': '$alias',
'name': { '$first': '$name' },
'id': { '$first': '$_id' }
}},
{ '$project': {
'alias': {
'$cond': [
{ '$eq': [ '$id', '$_id' ] },
null,
'$_id'
]
},
'name': 1,
'_id': '$id'
}}
])
哪个返回:
{ "_id" : "6", "name" : "Zoe", "alias" : "22" }
{ "_id" : "4", "name" : "Cristina", "alias" : null }
{ "_id" : "2", "name" : "Bob", "alias" : "4c" }
{ "_id" : "1", "name" : "Alice", "alias" : null }
到目前为止,一切都很好。
我需要根据“ dateOfBirth”字段对其进行排序。
非常有信心,我将查询更改为:
db.people.aggregate([
{ '$match': { 'flag': true } },
{ '$project': {
'name': 1,
'dateOfBirth': 1,
'alias': {
'$cond': [
{ '$eq': [ '$alias', null ] },
'$_id',
'$alias'
]
}
}},
{ '$group': {
'_id': '$alias',
'name': { '$first': '$name' },
'dateOfBirth': { '$first': '$dateOfBirth' },
'id': { '$first': '$_id' }
}},
{ '$project': {
'alias': {
'$cond': [
{ '$eq': [ '$id', '$_id' ] },
null,
'$_id'
]
},
'name': 1,
'_id': '$id',
'dateOfBirth': 1,
}},
{ '$sort': { 'dateOfBirth': 1 }}
])
但这给出了:
{ "_id" : "1", "name" : "Alice", "dateOfBirth" : ISODate("1995-12-27T00:00:00Z"), "alias" : null }
{ "_id" : "6", "name" : "Zoe", "dateOfBirth" : null, "alias" : "22" }
{ "_id" : "4", "name" : "Cristina", "dateOfBirth" : null, "alias" : null }
{ "_id" : "2", "name" : "Bob", "dateOfBirth" : null, "alias" : "4c" }
当然,这是错的:dateOfBirth
领域没有通过$group
舞台...
关于如何通过的任何线索?
实际上,这对我来说很好,并且我怀疑您正在运行的实际代码中有错别字(不是该清单),而在某处缺少了“ dateOfBirth”(或可能拼写错误)。
但是,如果这里要吸取教训,那就应该不要分头$project
,$group
分阶段,因为引入另一个管道阶段不仅效率低下(这意味着额外的数据传递),而且在指定要包含的数据时通常会造成混淆在管线中。
所以宁愿:
db.people.aggregate([
{ "$match": { "flag": true } },
{ "$group": {
"_id": {
"$ifNull": [ "$alias", "$_id" ]
},
"name": { "$first": "$name" },
"dateOfBirth": { "$first": "$dateOfBirth" },
"id": { "$first": "$_id" }
}},
{ "$project": {
"_id": "$id",
"name": 1,
"dateOfBirth": 1,
"alias": {
"$cond": [
{ "$eq": [ "$_id", "$id" ] },
null,
"$_id"
]
}
}},
{ "$sort": { "dateOfBirth": 1 } }
])
这也可以$ifNull
用作自然测试,而不是在$cond
不需要的地方使用。
当然,返回的结果是:
{ "_id" : "1", "name" : "Alice", "dateOfBirth" : ISODate("1995-12-27T00:00:00Z"), "alias" : null }
{ "_id" : "2", "name" : "Bob", "dateOfBirth" : ISODate("1996-12-27T00:00:00Z"), "alias" : "4c" }
{ "_id" : "4", "name" : "Cristina", "dateOfBirth" : ISODate("1998-12-27T00:00:00Z"), "alias" : null }
{ "_id" : "6", "name" : "Zoe", "dateOfBirth" : ISODate("2000-12-27T00:00:00Z"), "alias" : "22" }
如果您想“首先按生日”,则将排序移到$group
舞台之前,$first
操作员将在那里进行所有工作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句