使用聚合在Mongodb中的复杂条件中进行排序

Bru*_*tos 1 sorting mongodb aggregation-framework

我创建了一个关于使用已经解决的$ match的主题,但现在我陷入了一个更复杂的例子.例如,考虑我的Json的结构:

{
    user: 'bruno',
    answers: [
        {id: 0, value: 3.5},
        {id: 1, value: "hello"}
    ]
}
Run Code Online (Sandbox Code Playgroud)

我想添加或命令,对'value'中包含的值应用一些转换,只对标识符'id'等于0,例如sort方法.

请考虑以下数据:

db.my_collection.insert({ user: 'bruno', answers: [ {id: 0, value: 3.5}, {id: 1, value: "hello"}]})

db.my_collection.insert({ user: 'bruno2', answers: [ {id: 0, value: 0.5}, {id: 1, value: "world"}]})
Run Code Online (Sandbox Code Playgroud)

我试过用:

db.my_collection.aggregate ({$sort: {"answers": {"$elemMatch": {id: 0, value: -1}}}})
Run Code Online (Sandbox Code Playgroud)

但是,它没有用.预期结果是:{user:'bruno2'answers:[{id:0,value:0.5},{id:1,value:"world"}]},{user:'bruno'answers:[{id: 0,值:3.5},{id:1,value:"hello"}]})

谢谢.

小智 7

首先,请注意您的排序示例格式错误:aggregate方法将数组作为输入,其中数组中的每个元素指定聚合管道中的一个阶段.另请注意,$ elemMatch运算符不能用作$ sort阶段的一部分.

实现您尝试使用排序示例的一种方法是使用聚合框架的$ unwind管道运算符.展开数组会将数组元素逐个剥离到单独的文档中.例如,以下查询

db.my_collection.aggregate([ {$unwind: "$answers"} ]);
Run Code Online (Sandbox Code Playgroud)

返回如下内容:

[
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 0,
            "value" : 3.5
        }
    },
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 1,
            "value" : "hello"
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 0,
            "value" : 0.5
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 1,
            "value" : "world"
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

添加$ match阶段将允许您仅获取answers.id为零的文档.最后,$ sort阶段允许您按answers.value排序.聚合查询一起是:

db.my_collection.aggregate([
    {$unwind: "$answers"},
    {$match: {"answers.id": 0}},
    {$sort: {"answers.value": -1}}
]);
Run Code Online (Sandbox Code Playgroud)

并输出:

[
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 0,
            "value" : 3.5
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 0,
            "value" : 0.5
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

根据您的要求,听起来并不总是需要$ unwind甚至聚合框架.如果你想找到的文件的answers.id等于0,answers.value等于3.5,然后将answers.value更改为4你可以使用find和$ elemMatch,然后是db.collection.save():

doc = db.my_collection.findOne({"answers": {$elemMatch: {"id": 0, "value": 3.5}}});
for (i=0; i<doc.answers.length; i++) {
  if (doc.answers[i].id === 0) {
    doc.answers[i].value = 4;
    db.my_collection.save(doc);
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)