How to sort a collection using the last element of an array

自闭症网瘾萝莉.ら 提交于 2019-12-11 06:28:43

问题


My problem is that, i have a collection below, _id is ignored

{ "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" : [ ] }

And i what to sort it by the last value of array r, that is to say, i want to have a result below,

{ "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 } ] }

I know that i can sort by the first vaue of the array r by

db.my.find().sort({'r.0.v': 1})

But how can do it by the last value?

And, if with its mongoengine model below

class V(EmbeddedDocument):
    v = IntField()

class M(Document):
    value = IntFiled
    r = ListField(EmbeddedDocumentField(V))

How should i do with mongoengine? IntField maybe other fields such as DateTimeField, StringField ...

Thanks


回答1:


If possible, I'd suggest you just always (double) store the value you want to sort on. Put it in the array and in a second field. Whenever you push a new value to the array (or store the array), add a new field corresponding to the "last value in array" and then index and sort on that. In the example below, I called it 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" : [ ] }

Create an index:

db.so.ensureIndex({lastR: 1})

And then use:

> 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 }

It will be far more versatile and expandable than trying to use an aggregation solution (which will have a 16MB limit to the result set and makes it far more complex to retrieve complex documents when needing to deal with a projection).




回答2:


You can do this with the aggregation framework in the following way:

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 } }
] );

On your input data, this outputs:

{
    "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
}


来源:https://stackoverflow.com/questions/18126094/how-to-sort-a-collection-using-the-last-element-of-an-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!