如何查询包含嵌套数组子集的mongo文档

时间:2015-05-27 09:55:42

标签: mongodb meteor subset

这是我的文档:

var docIHave = {
    _id: "someId",
    things: [
        {
            name: "thing1",
            stuff: [1,2,3,4,5,6,7,8,9]
        },
        {
            name: "thing2",
            stuff: [4,5,6,7,8,9,10,11,12,13,14]
        },
        {
            name: "thing3",
            stuff: [1,4,6,8,11,21,23,30]
        }
    ]
}

这是我想要的文件:

var docIWant = {
    _id: "someId",
    things: [
        {
            name: "thing1",
            stuff: [5,6,7,8,9]
        },
        {
            name: "thing2",
            stuff: [5,6,7,8,9,10,11]
        },
        {
            name: "thing3",
            stuff: [6,8,11]
        }
    ]
}
  

docIWant的东西应该只包含大于min = 4的项目   小于max = 12。

背景: 我有一个流星应用程序,我订阅了一个给我docIHave的集合。根据参数min和max,我需要docisWant“动态”。不应修改原始文档。我需要一个查询或程序,它将docIWant返回给东西。

非常感谢实用的代码示例。

3 个答案:

答案 0 :(得分:2)

使用 aggregation framework 。在聚合管道中,将$match运算符视为您的第一个管道阶段。这对于优化聚合非常必要,因为您需要首先过滤与给定条件匹配的文档,然后再将其传递到管道上。

接下来使用$unwind运算符。这将从输入文档中解构things数组字段,以输出每个元素的文档。每个输出文档都是输入文档,其中数组字段的值由元素替换。

things.stuff数组也需要进行另一次$unwind操作。

然后,下一个管道阶段将过滤掉解构things.stuff与给定的最小和最大标准匹配的掺杂。请使用$match运算符。

然后,需要$group运算符按指定的标识符表达式对输入文档进行分组,并将累加器表达式$push应用于每个组。这会为每个组创建一个数组表达式。

通常你的聚合应该像这样结束(虽然我还没有真正测试过它,但这应该让你朝着正确的方向前进):

db.collection.aggregate([
    {
        "$match": {
            "things.stuff": { "$gt": 4, "$lte": 11 }
        }
    },
    {
        "$unwind": "$things"
    },
    {
        "$unwind": "$things.stuff"
    },
    {
        "$match": {
            "things.stuff": { "$gt": 4, "$lte": 11 }
        }
    },
    {
        "$group": {
            "_id": {
                "_id": "$_id",
                "things": "$things"
            },
            "stuff": {
                "$push": "$things.stuff"
            }
        }
    },
    {
        "$group": {
            "_id": "$_id._id",  
            "things": {
                "$push": {
                    "name": "$_id.things.name",
                    "stuff": "$stuff"
                }
            }
        }
    }
])

答案 1 :(得分:2)

如果您需要在客户端上转换文档以进行显示,您可以执行以下操作:

Template.myTemplate.helpers({
  transformedDoc: function() {
    // get the bounds - maybe these are stored in session vars
    var min = Session.get('min');
    var max = Session.get('max');

    // fetch the doc somehow that needs to be transformed
    var doc = SomeCollection.findOne();

    // transform the thing.stuff arrays
    _.each(doc.things, function(thing) {
      thing.stuff = _.reject(thing.stuff, function(n) {
        return (n < min) || (n > max);
      });
    });

    // return the transformed doc
    return doc;
  }
});

然后在您的模板中:{{#each transformedDoc.things}}...{{/each}}

答案 2 :(得分:1)

使用mongo aggregation如下: 首先使用$unwind这将取消stuff,然后使用$match查找大于4的元素。在基于things.name的{​​{3}}数据之后,在$project中添加必填字段。

查询如下:

db.collection.aggregate([
{
$unwind: "$things"
}, {
$unwind: "$things.stuff"
}, {
$match: {
    "things.stuff": {
        $gt: 4,
        $lt:12
    }
}
}, {
$group: {
    "_id": "$things.name",
    "stuff": {
        $push: "$things.stuff"
    }
}
}, {
$project: {
    "thingName": "$_id",
    "stuff": 1
}
}])