我的问题是,我有一个集合,_id被忽略
{ "value" : -10, "r" : [ { "v" : 1 }, { "v" : 3 } ] }
{ "value" : 2, "r" : [ { "v" : 4 }, { "v" : 1 } ] }
{ "value" : -100, "r" : [ { "v" : 4 }, { "v" : 1 }, { "v" : 10 } ] }
{ "value" : -3, "r" : [ ] }
我想用数组r的最后一个值对它进行排序,也就是说,我想在下面得到一个结果,
{ "value" : -3, "r" : [ ] } # this one should be either the first one or the last one
{ "value" : 2, "r" : [ { "v" : 4 }, { "v" : 1 } ] }
{ "value" : -10, "r" : [ { "v" : 1 }, { "v" : 3 } ] }
{ "value" : -100, "r" : [ { "v" : 4 }, { "v" : 1 }, { "v" : 10 } ] }
我知道我可以通过数组r的第一个vaue排序
db.my.find().sort({'r.0.v': 1})
但是怎么能用最后一个值来做呢?
并且,如果使用下面的mongoengine模型
class V(EmbeddedDocument):
v = IntField()
class M(Document):
value = IntFiled
r = ListField(EmbeddedDocumentField(V))
我应该如何处理mongoengine? IntField
可能是其他字段,例如DateTimeField
,StringField
...
由于
答案 0 :(得分:1)
您可以通过以下方式使用聚合框架执行此操作:
db.so.aggregate( [
// first we add the ``sortr`` field so that we can deal with empty arrays.
// if we see an empty array, we create one with a large negative number
{ $project: {
value: 1,
r: 1,
sortr: { $cond: [ { $eq : [ '$r', [] ] }, [ -100000 ], '$r' ] }
} },
// then we unwind on our sorting-r-variant
{ $unwind: '$sortr' },
// so that we can group by ID and pick out the last of the $sortr values
{ $group: {
_id: '$_id',
value: { $first: '$value' },
r: { $first: '$r' },
sortr: { $last: '$sortr' }
} },
// then we sort by the last items over all the documents
{ $sort: { sortr: 1 } },
// and reproject so that we get rid of the ``sortr`` field
{ $project: { value: 1, r: 1 } }
] );
在输入数据上输出:
{
"result" : [
{
"_id" : ObjectId("520391bd0cc1fa3c84416e9a"),
"value" : -3,
"r" : [ ]
},
{
"_id" : ObjectId("520391a70cc1fa3c84416e98"),
"value" : 2,
"r" : [ { "v" : 4 }, { "v" : 1 } ]
},
{
"_id" : ObjectId("520391a10cc1fa3c84416e97"),
"value" : -10,
"r" : [ { "v" : 1 }, { "v" : 3 } ]
},
{
"_id" : ObjectId("520391ad0cc1fa3c84416e99"),
"value" : -100,
"r" : [ { "v" : 4 }, { "v" : 1 }, { "v" : 10 } ]
}
],
"ok" : 1
}
答案 1 :(得分:1)
如果可能的话,我建议你总是(双倍)存储你想要排序的值。将它放在数组和第二个字段中。每当您将新值推送到数组(或存储数组)时,添加一个对应于“数组中的最后一个值”的新字段,然后对其进行索引和排序。在下面的示例中,我将其称为lastR
:
{ "value" : -10, "r" : [ { "v" : 1 }, { "v" : 3 } ], "lastR": 3 }
{ "value" : 2, "r" : [ { "v" : 4 }, { "v" : 1 } ], "lastR": 1 }
{ "value" : -100, "r" : [ { "v" : 4 }, { "v" : 1 }, { "v" : 10 } ], "lastR": 10 }
{ "value" : -3, "r" : [ ] }
创建索引:
db.so.ensureIndex({lastR: 1})
然后使用:
> db.so.find().sort({lastR: 1})
{ "_id" : ObjectId("5203a1c83c5438af60de63a1"), "value" : -3, "r" : [ ] }
{ "_id" : ObjectId("5203a1ad3c5438af60de639f"), "value" : 2, "r" : [ { "v" : 4 }, { "v" : 1 } ], "lastR" : 1 }
{ "_id" : ObjectId("5203a1d33c5438af60de63a2"), "value" : -10, "r" : [ { "v" : 1 }, { "v" : 3 } ], "lastR" : 3 }
{ "_id" : ObjectId("5203a1b73c5438af60de63a0"), "value" : -100, "r" : [ { "v" : 4 }, { "v" : 1 }, { "v" : 10 } ], "lastR" : 10 }
与尝试使用聚合解决方案相比,它将更具通用性和可扩展性(聚合解决方案对结果集的限制为16MB,并且在需要处理投影时检索复杂文档会更加复杂)。