使用聚合在Mongodb中的复杂条件中排序 [英] Using aggregation to sorting in complex conditional in Mongodb

查看:611
本文介绍了使用聚合在Mongodb中的复杂条件中排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  {
user:'bruno',
:[
{id:0,value:3.5},
{id:1,value:hello}
]
}

我想添加或排序,对'value'中包含的值只应用标识符'id'等于0的一些变换例如排序方法。



考虑以下数据:

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

我尝试使用:

  db.my_collection.aggregate {$ sort:{answers:{$ elemMatch:{id:0,value:-1}}}})

但是,它没有工作。预期的结果是:
{user:'bruno2'answers:[{id:0,value:0.5},{id:1,value:world}]},
{user: bruno的答案:[{id:0,value:3.5},{id:1,value:hello}]})



谢谢。 >

解决方案

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



一个方法来实现你想要做的排序的例子是使用聚合框架的 $ unwind 管道操作符。展开数组会将数组元素逐个分离成单独的文档。例如,以下查询

  db.my_collection.aggregate([{$ unwind:$ answers}]); 

返回如下所示的内容:

  [
{
_id:ObjectId(5237157f3fac8e36fdb0b96e),
user:bruno,
answers {
id:0,
value:3.5
}
},
{
_id:ObjectId(5237157f3fac8e36fdb0b96e) ,
user:bruno,
answers:{
id:1,
value:hello
} $ b},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:0,
value:0.5
}
},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:1,
value:world
}
} $ b b]

添加$ match阶段将允许您仅抓取answer.id为零的文档。最后,$ sort阶段允许你按answers.value排序。汇总查询是:

  db.my_collection.aggregate([
{$ unwind:$ answers },
{$ match:{answers.id:0}},
{$ sort:{answers.value:-1}}
]

输出:

  [
{
_id:ObjectId(5237157f3fac8e36fdb0b96e),
user:bruno,
answers:{
id:0,
value:3.5
}
},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:0,
value:0.5
}
} b $ b]

根据你的要求, $ unwind甚至聚合框架。如果相反,你想找到answer.id等于0和answers.value等于3.5的文档,然后将answers.value更改为4,你可以使用find with $ 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;
}
}


I create a topic about using $match which was solved, but now I'm stuck in a more complex example. For example, consider the struct of my Json:

{
    user: 'bruno',
    answers: [
        {id: 0, value: 3.5},
        {id: 1, value: "hello"}
    ]
}

I would like to add or order, apply some transformations on the values contained in 'value' only the identifier 'id' equal to 0, for example a sort method.

Consider the following data:

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

I tried using:

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

But, it didn't work. The expected result was: {user: 'bruno2' answers: [{id: 0, value: 0.5}, {id: 1, value: "world"}]}, {user: 'bruno' answers: [{id: 0, value: 3.5}, {id: 1, value: "hello"}]})

Thank you.

解决方案

First, note that your sort example is malformed: the aggregate method takes an array as input, where each element in the array specifies a stage in an aggregation pipeline. Also, note that the $elemMatch operator cannot be used as part of a $sort stage.

One way to achieve what you're trying to do with your sort example is use the aggregation framework's $unwind pipeline operator. Unwinding an array will peel the array elements off one-by-one into separate documents. For example, the following query

db.my_collection.aggregate([ {$unwind: "$answers"} ]);

returns something like the following:

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

Adding a $match phase will allow you to grab only the documents where answers.id is zero. Finally, a $sort phase allows you to sort by answers.value. All together the aggregation query is:

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

And the output:

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

Based on what your asking, it doesn't sound like you'll always need $unwind or even the aggregation framework. If instead you wanted to find the document with answers.id equal to 0 and answers.value equal to 3.5, and then change answers.value to 4 you could use find with $elemMatch followed by 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;
  }
}

这篇关于使用聚合在Mongodb中的复杂条件中排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆