1

我的问题是,我在下面有一个集合,_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 的第一个值排序

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也许其他领域,例如DateTimeFieldStringField...

谢谢

4

2 回答 2

3

如果可能的话,我建议你总是(双)存储你想要排序的值。将其放入数组和第二个字段中。每当您将新值推送到数组(或存储数组)时,添加一个与“数组中的最后一个值”相对应的新字段,然后对其进行索引和排序。在下面的示例中,我将其称为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 的限制,并且在需要处理投影时检索复杂文档变得更加复杂)更加通用和可扩展。

于 2013-08-08T13:53:08.433 回答
2

您可以通过以下方式使用聚合框架执行此操作:

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
}
于 2013-08-08T13:00:34.613 回答