MongoDB';条款保函中的s$

MongoDB';条款保函中的s$,mongodb,mongoose,mapreduce,mongodb-query,aggregation-framework,Mongodb,Mongoose,Mapreduce,Mongodb Query,Aggregation Framework,使用MongoDB子句时,返回文档的顺序是否始终与数组参数的顺序相对应?始终?从未。顺序始终相同:未定义(可能是存储文档的物理顺序)。除非对其进行排序。如前所述,$in子句数组中参数的顺序并不反映检索文档的顺序。当然,这将是自然顺序或所选索引顺序,如图所示 如果你需要保持这个顺序,那么你基本上有两个选择 假设您将文档中\u id的值与一个数组进行匹配,该数组将作为[4,2,8]传入$in 使用聚合的方法 var列表=[4,2,8]; db.collection.aggregate([ //按“

使用MongoDB子句时,返回文档的顺序是否始终与数组参数的顺序相对应?

始终?从未。顺序始终相同:未定义(可能是存储文档的物理顺序)。除非对其进行排序。

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

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

假设您将文档中
\u id
的值与一个数组进行匹配,该数组将作为
[4,2,8]
传入
$in

使用聚合的方法
var列表=[4,2,8];
db.collection.aggregate([
//按“\u id”匹配所选文档
{“$match”:{
“_id”:{“$in”:[4,2,8]},
},
//为每个文档投影一个“权重”
{“$project”:{
“重量”:{“$cond”:[
{“$eq”:[“$_id”,4]},
1.
{“$cond”:[
{“$eq”:[“$_id”,2]},
2.
3.
]}
]}
}},
//对结果进行排序
{“$sort”:{“权重”:1}
])
这就是扩展的形式。这里基本上发生的事情是,正如值数组被传递给
$in
一样,您还构造了一个“嵌套的”
$cond
语句来测试值并分配适当的权重。作为“权重”值反映数组中元素的顺序,然后可以将该值传递给排序阶段,以便按所需顺序获得结果

当然,您实际上是在代码中“构建”管道语句,就像这样:

var列表=[4,2,8];
var堆栈=[];
对于(var i=list.length-1;i>0;i--){
var rec={
“$cond”:[
{“$eq”:[“$_id”,列表[i-1]},
我
]
};
if(stack.length==0){
rec[“$cond”].推送(i+1);
}否则{
var lval=stack.pop();
rec[“$cond”].推送(lval);
}
堆栈推送(rec);
}
变量管道=[
{“$match”:{“\u id”:{“$in”:list}},
{“$project”:{“权重”:堆栈[0]},
{“$sort”:{“权重”:1}
];
db.收集.聚合(管道);
使用mapReduce的方法
当然,如果这一切似乎对你的敏感度有很大影响,那么你可以使用mapReduce做同样的事情,它看起来更简单,但运行速度可能会慢一些

var列表=[4,2,8];
db.collection.mapReduce(
函数(){
变量顺序=inputs.indexOf(此._id);
emit(顺序,{doc:this});
},
函数(){},
{ 
“out”:{“inline”:1},
“查询”:{“_id”:{“$in”:list},
“范围”:{“输入”:列表},
“最终确定”:功能(键、值){
返回值.doc;
}
}
)
这基本上取决于发出的“键”值在输入数组中的“索引顺序”



因此,这些基本上是您在条件下将输入列表的顺序保持为$的方法,您已经以确定的顺序拥有了该列表。

如果您不想使用聚合,另一种解决方案是使用查找,然后使用以下命令在客户端对文档结果进行排序:

如果中的
$值是数字等基本类型,则可以使用以下方法:

varids=[4,2,8,1,9,3,5,6];
find({u id:{$in:ids}}).exec(函数(err,docs){
文档排序(功能(a、b){
//按照文档在id中的_id值的顺序对文档进行排序。
返回id.indexOf(a.\u id)-id.indexOf(b.\u id);
});
});
如果
中的
$值是非基本类型,如
ObjectId
s,则需要另一种方法,因为在这种情况下,
indexOf
通过引用进行比较

如果您使用的是Node.js 4.x+,则可以使用并通过将
排序
函数更改为:

docs.sort((a,b)=>ids.findIndex(id=>a._id.equals(id))-
id.findIndex(id=>b._id.equals(id));
或任何Node.js版本,带下划线/lodash:

docs.sort(函数(a,b){
return u.findIndex(id,函数(id){returna.id.equals(id);})-
_.findIndex(id,函数(id){返回b._id.equals(id);});
});

您可以使用$or条款保证订单

因此,请改用
$或:[u id.map({u id}))]

与的解决方案类似,您可以在客户端(如果您的客户端是JavaScript)中使用
map
和EcmaScript 2015中的
数组.prototype.find
函数组合,对从
find
返回的文档进行重新排序:

Collection.find({ _id: { $in: idArray } }).toArray(function(err, res) {

    var orderedResults = idArray.map(function(id) {
        return res.find(function(document) {
            return document._id.equals(id);
        });
    });

});
几点注意:

  • 以上代码使用的是Mongo节点驱动程序和Mongoose
  • idArray
    ObjectId
  • 我还没有测试过该方法与排序方法的性能,但是如果您需要操作每个返回的项(这非常常见),您可以在
    map
    回调中进行操作,以简化代码

这是从Mongo检索结果后的代码解决方案。使用映射存储索引,然后交换值

catDetails := make([]CategoryDetail, 0)
err = sess.DB(mdb).C("category").
    Find(bson.M{
    "_id":       bson.M{"$in": path},
    "is_active": 1,
    "name":      bson.M{"$ne": ""},
    "url.path":  bson.M{"$exists": true, "$ne": ""},
}).
    Select(
    bson.M{
        "is_active": 1,
        "name":      1,
        "url.path":  1,
    }).All(&catDetails)

if err != nil{
    return 
}
categoryOrderMap := make(map[int]int)

for index, v := range catDetails {
    categoryOrderMap[v.Id] = index
}

counter := 0
for i := 0; counter < len(categoryOrderMap); i++ {
    if catId := int(path[i].(float64)); catId > 0 {
        fmt.Println("cat", catId)
        if swapIndex, exists := categoryOrderMap[catId]; exists {
            if counter != swapIndex {
                catDetails[swapIndex], catDetails[counter] = catDetails[counter], catDetails[swapIndex]
                categoryOrderMap[catId] = counter
                categoryOrderMap[catDetails[swapIndex].Id] = swapIndex
            }
            counter++
        }
    }
}
catDetails:=make([]类别详细信息,0)
err=sess.DB(mdb.C(“类别”)。
查找(bson.M){
“_id”:bson.M{“$in”:path},
“是否处于活动状态”:1,
“名称”:bson.M{“$ne”:“},
“url.path”:bson.M{“$exists”:true,$ne:”},
}).
挑选(
bson.M{
“是否处于活动状态”:1,
“名称”:1,
“url.path”:1,
}).所有(&catDetails)
如果错误!=零{
返回
}
categoryOrderMap:=make(映射[int]int)
对于索引,v:=范围catDetails{
categoryOrderMap[v.Id]=索引
}
计数器:=0
对于i:=0;计数器<
  obj.map = function() {
    for(var i = 0; i < inputs.length; i++){
      if(this._id.equals(inputs[i])) {
        var order = i;
      }
    }
    emit(order, {doc: this});
  };
things = list(db.things.find({'_id': {'$in': id_array}}))
things.sort(key=lambda thing: id_array.index(thing['_id']))
# things are now sorted according to id_array order
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);
async function batchUsers(Users, keys) {
  const unorderedUsers = await Users.find({_id: {$in: keys}}).toArray()
  let obj = {}
  unorderedUsers.forEach(x => obj[x._id]=x)
  const ordered = keys.map(key => obj[key])
  return ordered
}
  const idList = ['123', '124', '125']
  const out = await db
    .collection('YourCollection')
    .aggregate([
      // Change uuid to your `id` field
      { $match: { uuid: { $in: idList } } },
      {
        $project: {
          uuid: 1,
          date: 1,
          someOtherFieldToPreserve: 1,
          // Addding this new field called index
          index: {
            // If we want index to start from 1, add an dummy value to the beggining of the idList array
            $indexOfArray: [[0, ...idList], '$uuid'],
            // Otherwise if 0,1,2 is fine just use this line
            // $indexOfArray: [idList, '$uuid'],
          },
        },
      },
      // And finally sort the output by our index
      { $sort: { index: 1 } },
    ])