如果您使用.find() 查看标准投影,那么“排序”或“展平”数组成员确实没有太多选择,但如果元素已经有序,这是您最快的选择:
db.test.find({},{
"Abc": { "$slice": -1 },
"Ghi": { "$slice": -1 },
"Xyz": { "$slice": -1 }
})
有了它的输出:
{
"_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
"Abc" : [{ "_id" : 3, "val" : "new new value" }],
"Xyz" : [{ "_id" : 3, "val" : 21342 }],
"Ghi" : [{ "_id" : 3, "val" : "new new value" }]
}
{
"_id" : ObjectId("537d87fe348f6339113e85ae"),
"Abc" : [{ "_id" : 3, "val" : "new new value" }],
"Ghi" : [{ "_id" : 3, "val" : "new new value" }]
}
如果您准备提名所有可能的字段,则可以使用聚合框架执行类似的操作:
db.test.aggregate([
{ "$project": {
"Abc": { "$ifNull": [ "$Abc", [ false ] ] },
"Ghi": { "$ifNull": [ "$Ghi", [ false ] ] },
"Xyz": { "$ifNull": [ "$Xyz", [ false ] ] }
}},
{ "$unwind": "$Abc" },
{ "$unwind": "$Ghi" },
{ "$unwind": "$Xyz" },
{ "$sort": { "Abc._id": -1, "Ghi._id": -1, "Xyz": -1 } },
{ "$group": {
"_id": "$_id",
"Abc": { "$first": "$Abc.val" },
"Ghi": { "$first": "$Ghi.val" },
"Xyz": { "$first": "$Xyz.val" }
}}
])
如果使用$ifNull 运算符阻止后面的$unwind 语句爆炸,则如果该字段不存在,这实质上会在其中放置一个[ false ] 数组。关于这是否适合您的解决方案,里程可能会有所不同。它的输出:
{
"_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
"Abc" : "new new value",
"Ghi" : "new new value",
"Xyz" : 21342
}
{
"_id" : ObjectId("537d87fe348f6339113e85ae"),
"Abc" : "new new value",
"Ghi" : "new new value",
"Xyz" : null
}
您也可以使用 mapReduce 做一些更复杂的事情,即使没有进行实际的缩减:
db.test.mapReduce(
function () {
for ( var k in this ) {
if ( k === '_id' )
continue;
this[k].sort(function(a, b) {
if ( a._id < b._id ) {
return -1;
} else if ( a._id > b._id ) {
return 1;
}
return 0;
});
this[k] = this[k].slice(-1)[0].val;
}
var id = this._id;
delete this["_id"];
emit( id, this );
},
function(){},
{
"out": { "inline": 1 }
}
)
它的 mapReduce 输出很糟糕,但至少你可以灵活地使用文档中的“键”:
"results" : [
{
"_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
"value" : {
"Abc" : "new new value",
"Xyz" : 21342,
"Ghi" : "new new value"
}
},
{
"_id" : ObjectId("537d87fe348f6339113e85ae"),
"value" : {
"Abc" : "new new value",
"Ghi" : "new new value"
}
}
]
因此,这是考虑到他们个人优势和劣势的一些方法,但也是完成工作的一种方式。