当前位置: 首页 > 知识库问答 >
问题:

MongoDB的$in条款保证令吗

江亮
2023-03-14

使用MongoDB的$in子句时,返回文档的顺序是否总是对应于数组参数的顺序?

共有3个答案

澹台举
2023-03-14

如果您不想使用聚合,另一个解决方案是使用查找,然后使用数组#sort

如果< code>$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) {
        // Sort docs by the order of their _id values in ids.
        return ids.indexOf(a._id) - ids.indexOf(b._id);
    });
});

如果< code>$in值是非基元类型,如< code>ObjectIds,则需要另一种方法,因为< code>indexOf在这种情况下通过引用进行比较。

如果您正在使用节点。js 4.x,您可以使用Array#findIndexObjectID#equals来处理此问题,方法是将 function更改为:

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

或者使用任何Node.js版本,使用下划线/拉达什的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); });
});
百里成仁
2023-03-14

使用仅适用于MongoDB版本的聚合查询的另一种方法

这归功于这篇漂亮的博文。

按此顺序提取的示例文档-

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

文章中的另一个引用解释了这些聚合运算符的使用-

“$addFields”阶段在3.4中是新的,它允许您在不知道所有其他现有字段的情况下将新字段“$project”到现有文档中。新的“$indexOfArray”表达式返回给定数组中特定元素的位置。

基本上,当<code>addFields</code>操作符找到每个文档时,它会将一个新的<code>order</code>字段附加到每个文档中,这个<code>订单</code>字段表示我们提供的数组的原始顺序。然后我们简单地根据这个字段对文档进行排序。

万俟浩
2023-03-14

如前所述,$in子句数组中参数的顺序并不反映检索文档的顺序。这当然是自然顺序或如图所示的所选索引顺序。

如果你需要保留这个顺序,那么你基本上有两个选择。

假设您正在将文档中的< code>_id的值与一个数组进行匹配,该数组将作为< code>[ 4,2,8 ]传递给< code>$in。

var list = [ 4, 2, 8 ];

db.collection.aggregate([

    // Match the selected documents by "_id"
    { "$match": {
        "_id": { "$in": [ 4, 2, 8 ] },
    },

    // Project a "weight" to each document
    { "$project": {
        "weight": { "$cond": [
            { "$eq": [ "$_id", 4  ] },
            1,
            { "$cond": [
                { "$eq": [ "$_id", 2 ] },
                2,
                3
            ]}
        ]}
    }},

    // Sort the results
    { "$sort": { "weight": 1 } }

])

这就是扩展形式。这里基本上发生的事情是,正如值数组在中传递给$一样,您还构造了一个“嵌套”$cond语句来测试这些值并分配适当的权重。由于“权重”值反映了数组中元素的顺序,因此您可以将该值传递到排序阶段,以便按所需的顺序获得结果。

当然,您实际上是在代码中“构建”管道语句,如下所示:

js prettyprint-override">var list = [ 4, 2, 8 ];

var stack = [];

for (var i = list.length - 1; i > 0; i--) {

    var rec = {
        "$cond": [
            { "$eq": [ "$_id", list[i-1] ] },
            i
        ]
    };

    if ( stack.length == 0 ) {
        rec["$cond"].push( i+1 );
    } else {
        var lval = stack.pop();
        rec["$cond"].push( lval );
    }

    stack.push( rec );

}

var pipeline = [
    { "$match": { "_id": { "$in": list } }},
    { "$project": { "weight": stack[0] }},
    { "$sort": { "weight": 1 } }
];

db.collection.aggregate( pipeline );

当然,如果这一切对你的敏感度来说都很重要,那么你可以使用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;
        }
    }
)

这基本上依赖于发出的“键”值在输入数组中出现的“索引顺序”。

所以这些基本上是你维护一个输入列表的顺序到一个< code>$in条件的方法,你已经有了一个确定的顺序的列表。

 类似资料:
  • 问题内容: 我有以下代码: 而当的输出是 问题是:我想要变量的原始顺序。 所有这些都是在IPython Notebook中完成的。有什么方法可以保持秩序? 问题答案: 可悲的是,SymPy无法跟踪输入顺序(请参阅我在对该问题的评论中链接的另一个问题)。您可以定义自己的排序函数,以便根据需要对表达式进行排序,但是由于无法保存信息,因此无法完全按照输入的顺序对它们进行排序。

  • 条款 当您访问 https://casbin.org 时,我们认为您同意如下条款及适用的法律法规,并且对相应的法律法规负责。 如果您不同意其中的任何一条,那您将没有权限访问或使用我们的网站。 此网站的所有资源均受到相应版权和商标法的保护。 使用许可证 当您从 Casbin 官网下载资料副本(信息或者软件)时,我们将授予您一份临时许可,仅供您个人的非商业阅览。 我们仅授权您使用,但并不将产权转让给您

  • 条款30:确保目标区间足够大 STL容器在被添加时(通过insert、push_front、push_back等)自动扩展它们自己来容纳新对象。这工作的很好,有些程序员因为这个信仰而被麻痹,认为他们不必担心要为容器中的对象腾出空间,因为容器自己可以照顾好这些。如果是那样就好了!当程序员想向容器中插入对象但并没有告诉STL他们所想的时,问题出现了。这是一个常见的可以自我表现的方法: int tra

  • 条款6:警惕C++最令人恼怒的解析 假设你有一个int的文件,你想要把那些int拷贝到一个list中。这看起来像是一个合理的方式: ifstream dataFile("ints.dat"); list<int> data(istream_iterator<int>(dataFile), // 警告!这完成的并不 istream_iterator<int>()); // 是像你想象的那样

  • 我想知道Azure Cosmos DB是否通过MongoDB API完全支持MongoDBhttps://docs.microsoft.com/es-es/azure/cosmos-db/mongodb-introduction 我读到聚合管道、map-duce和全文索引没有完全集成。有人有关于它的更多信息吗?考虑到MongoDB的当前状态,您会在Azure Cosmos DB中使用它吗?

  • 在本章中,您将了解常用的Excel VBA术语。 这些术语将用于其他模块,因此理解其中的每一个都很重要。 单元 (Modules) 模块是编写代码的区域。 这是一个新的工作簿,因此没有任何模块。 要插入模块,请导航到“插入”→“模块”。 插入模块后,将创建“module1”。 在模块中,我们可以编写VBA代码,代码在过程中编写。 过程/子过程是一系列VBA语句,用于指示要执行的操作。 过程 (Pr