是否可能按照列表的顺序对Mongo查询进行排序?

28 浏览
0 Comments

是否可能按照列表的顺序对Mongo查询进行排序?

在使用MongoDB的$in子句时,返回的文档顺序是否始终与数组参数的顺序一致?

0
0 Comments

在MongoDB中,使用$in子句的数组参数的顺序并不反映检索文档的顺序,而是按照自然顺序或选定的索引顺序进行检索。如果需要保留这个顺序,可以有两种选项。

第一种方法是使用聚合(aggregate)操作:

var list = [ 4, 2, 8 ];
db.collection.aggregate([
    { "$match": {
        "_id": { "$in": [ 4, 2, 8 ] },
    },
    { "$project": {
        "weight": { "$cond": [
            { "$eq": [ "$_id", 4  ] },
            1,
            { "$cond": [
                { "$eq": [ "$_id", 2 ] },
                2,
                3
            ]}
        ]}
    }},
    { "$sort": { "weight": 1 } }
])

第二种方法是使用mapReduce操作:

var list = [ 4, 2, 8 ];
db.collection.mapReduce(
    function () {
        var order = inputs.indexOf(this._id);
        emit( order, { doc: this } );
    },
    function() {},
    { 
        "out": { "inline": 1 },
        "query": { "_id": { "$in": list } },
        "scope": { "inputs": list } ,
        "finalize": function (key, value) {
            return value.doc;
        }
    }
)

以上就是在$in条件中保持输入列表顺序的两种方法。第一种方法使用聚合操作,通过构建一个嵌套的$cond语句来测试值并分配适当的权重,然后通过排序阶段将该权重值传递给结果以获取所需的顺序。第二种方法使用mapReduce操作,依赖于发射的键值在输入数组中按照索引顺序出现。

如果数组项是对象ID,则使用聚合方法的性能如何,这个问题没有给出明确的答案。

0
0 Comments

问题的出现原因是希望按照一个列表的顺序对Mongo查询结果进行排序,但是MongoDB不直接支持按照列表顺序排序的功能。为了解决这个问题,可以使用find方法查询结果后,在客户端使用JavaScript数组的sort方法进行排序。

如果$in的值是原始类型(如数字),可以使用以下方法:

var ids = [4, 2, 8, 1, 9, 3, 5, 6];
MyModel.find({ _id: { $in: ids } }).exec(function(err, docs) {
    docs.sort(function(a, b) {
        // 根据ids中_id的顺序对docs进行排序
        return ids.indexOf(a._id) - ids.indexOf(b._id);
    });
});

如果$in的值是非原始类型(如ObjectId),则需要使用不同的方法,因为indexOf方法在这种情况下会比较引用。如果使用Node.js 4.x+,可以使用Array#findIndex和ObjectID#equals来处理,将sort函数改为:

docs.sort((a, b) => ids.findIndex(id => a._id.equals(id)) - 
                    ids.findIndex(id => b._id.equals(id)));

或者在任何Node.js版本中,可以使用underscore/lodash的findIndex:

docs.sort(function (a, b) {
    return _.findIndex(ids, function (id) { return a._id.equals(id); }) -
           _.findIndex(ids, function (id) { return b._id.equals(id); });
});

其中,equals函数是Mongoose的Document#equals方法,用于比较文档的_id字段。

0
0 Comments

在MongoDB版本 >= 3.4中,可以使用聚合查询的另一种方法来按列表顺序排序查询结果。以下是解决方法的具体内容:

首先,我们需要一个示例文档,并按照特定顺序提取这些文档。例如,我们有以下文档:

var order = [ "David", "Charlie", "Tess" ];

接下来,我们可以使用聚合查询来实现按照指定顺序排序的功能。查询如下:

var query = [
             {$match: {name: {$in: order}}},
             {$addFields: {"__order": {$indexOfArray: [order, "$name" ]}}},
             {$sort: {"__order": 1}}
            ];
var result = db.users.aggregate(query);

上述查询中的聚合操作符的含义如下:

- `$match`:匹配name字段在order列表中的文档

- `$addFields`:添加一个名为`__order`的新字段,该字段的值为name在order列表中的索引位置

- `$sort`:根据`__order`字段的值进行升序排序

这样,我们就可以按照指定顺序对文档进行排序。

此外,可以通过将order数组存储为查询的变量来避免在查询中重复使用相同的数组。这样可以简化查询语句,特别是当数组很大时。具体实现方法可以参考以下代码:

var order = new[] { "David", "Charlie", "Tess" };
var query = new BsonDocument[]
{
    new BsonDocument("$match", new BsonDocument("name", new BsonDocument("$in", new BsonArray(order)))),
    new BsonDocument("$addFields", new BsonDocument("__order", new BsonDocument("$indexOfArray", new BsonArray(new BsonValue[] { new BsonArray(order), "$name" })))),
    new BsonDocument("$sort", new BsonDocument("__order", 1))
};
var result = collection.Aggregate(query).ToList();

以上是将MongoDB中按照列表顺序排序查询结果的方法以及如何在C#的LINQ中实现的思路和代码。

0