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

How do I query a mongo document containing subset of nested array

这是我的文档:

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

stuff´s of docIWant should only contain items greater than min=4 and smaller than max=12.

背景: 我有一个流星应用程序,我订阅了一个给我 docIHave 的集合。基于参数 min 和 max,我需要 docIWant "on the fly"。不得修改原始文件。我需要一个查询或过程 returns 我 docIWant 与东西的子集。

一个实用的代码示例将不胜感激。

使用 mongo aggregation 如下所示: 先在things.name基础上使用$unwind this will unwind stuff and then use $match to find elements greater than 4. After that $group数据,在$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
}
}])

使用 aggregation framework for this. In the aggregation pipeline, consider the $match 运算符作为您的第一个管道阶段。这对于优化您的聚合非常必要,因为您需要先过滤符合给定条件的文档,然后再将它们传递到管道的下方。

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

things.stuff 数组也需要另一个 $unwind 操作。

下一个流水线阶段将过滤文档,其中解构的 things.stuff 符合给定的最小和最大标准。为此使用 $match 运算符。

每组一个$group operator is then required to group the input documents by a specified identifier expression and applies the accumulator expression $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"
                }
            }
        }
    }
])

如果您需要在客户端转换文档以供显示,您可以这样做:

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}}