使用Golang mgo.v2嵌套MongoDB查询

时间:2016-09-15 13:31:19

标签: mongodb go

我正在查询带有嵌套数组项的json结构。我想返回整个结构,但只包括与查询条件匹配的嵌套项。

所以 - 样本结构是

{
     parentId:1,
     items: [
            {
               field1: 1
               field2: 2
            },
            {
               field1: 3
               field2: 4
            }
            ]
}

我想查询类似的内容 - >

db.getCollection('mycollection').find({"items.field1":1, "items.field2":2}) 

这有效,但它也会带回第二个子项目,我希望它实际返回的是这个 - >

{
     parentId:1,
     items: [
            {
               field1: 1
               field2: 2
            }
            ]
}

我已经能够在MongoDB中创建一个查询来实现我想要的 - >

db.getCollection('mycollection').aggregate(
  { $unwind : "$items" },
  { $match : {
     "items.field1": 1,
     "items.field2": 2,
  }}
)

但是当尝试使用mgo.v2设置它时,它证明了一点母马。 collection.Find方法似乎不喜欢$ unwind命令,似乎无法使用正确的语法来使用Pipe方法。

有没有人有任何建议如何创建?我可以创建字符串并将其传递执行吗?

2 个答案:

答案 0 :(得分:2)

您需要的实际管道涉及使用 $filter 运算符,该运算符根据指定的条件选择要返回的数组子集。它返回一个数组,其中只包含与条件匹配的元素。

在您的情况下,您需要运行以下聚合操作

db.mycollection.aggregate([
   {
        "$project": {
            "parentId": 1,          
            "items": {
                "$filter": {
                    "input": "$items",
                    "as": "item",
                    "cond": { 
                        "$and": [
                            { "$eq": ["$$item.field1", 1] },
                            { "$eq": ["$$item.field2", 2] }
                        ]
                    }
                }
            }
        }
    }
])

<强>测试 enter image description here

对于不支持 $filter 运算符的MongoDB版本,您可以使用set operators的组合作为:

db.mycollection.aggregate([
   {
        "$project": {
            "parentId": 1,          
            "items": {
                "$setDifference": [
                    { "$map": {
                        "input": "$items",
                        "as": "item",
                        "in": {
                            "$cond": [
                               { 
                                    "$and": [
                                        { "$eq": ["$$item.field1", 1] },
                                        { "$eq": ["$$item.field2", 2] }
                                    ]
                                },
                                "$$item",
                                false
                            ]
                        }
                    }},
                    [false]
                ]
            }
        }
    }
])

作为最后的手段,您可以使用 $unwind 运算符,因为运算符会为每个数组条目生成每个文档的副本,该副本使用更多内存(聚合管道上的可能内存上限为10)总内存百分比)因此也需要时间来产生以及处理的“时间”。您可以运行:

db.mycollection.aggregate([
    { "$unwind" : "$items" },
    { "$match" : {
        "items.field1": 1,
        "items.field2": 2,
    }},
    {
        "$group": {
            "_id": "$_id",
            "parentId": { "$first": "$parentId" },
            "items": { "$push": "$items" }
        }
    }
])

您可以在mgo中以pipeline

的形式运行
pipeline := []bson.M{   
    bson.M{ "$unwind": "$items" },
    bson.M{
        "$match": bson.M{ 
            "items.field1": 1,
            "items.field2": 2
        }
    },
    bson.M{
        "$group": bson.M{
            "_id": "$_id",
            "parentId": bson.M{ "$first": "$parentId" },
            "items": bson.M{ "$push": "$items" }
        }
    }   
}
pipe := mycollection.Pipe(pipeline)
iter := pipe.Iter()

在Robomongo进行测试

enter image description here

答案 1 :(得分:1)

参考chridam's answer,我相信$filter可以简化一下:

c := session.DB("test").C("mycollection")

pipe := c.Pipe([]bson.M{{
    "$project": bson.M{
        "parentId": 1,
        "items": bson.M{
            "$filter": bson.M{
                "input": "$items",
                "as":    "item",
                "cond": bson.M{
                    "$and": []bson.M{
                        {"$eq": []interface{}{"$$item.field1", 1}},
                        {"$eq": []interface{}{"$$item.field2", 2}},
                    },
                },
            },
        },
    },
}})

resp := []bson.M{}
err = pipe.All(&resp)

if err != nil {
    panic(err)
}

fmt.Println(resp)

另一个$unwind

c := session.DB("test").C("mycollection")

pipe := c.Pipe([]bson.M{
    {"$unwind": "$items"},
    {"$match": bson.M{
        "items.field1": 1,
        "items.field2": 2,
    }},
    {"$group": bson.M{
        "_id":      "$_id",
        "parentId": bson.M{"$first": "$parentId"},
        "items":    bson.M{"$push": "$items"},
    }},
})

resp := []bson.M{}
err = pipe.All(&resp)

if err != nil {
    panic(err)
}

fmt.Println(resp) 

两者都编译没有错误并返回

[map[
    _id:ObjectIdHex(".....") 
    parentId:1 
    items:[map[
        field2:2 
        field1:1
    ]]
]]

去1.6,mongo 3.2