Mongodb返回多个子数组结果并排除其他返回的结果

时间:2015-08-31 15:34:56

标签: mongodb mongodb-query aggregation-framework

我有以下带有节点数组的集合:

{
"_id" : ObjectId("55acf6187d4c31475417fa62"),
"node" : [
    {
        "-id" : "29331496",
        "-uid" : "1899168",
        "-changeset" : "26313303",
        "-lat" : "-37.6104102",
        "-lon" : "144.9459817",
        "-timestamp" : "2014-10-25T03:36:51Z",
        "-user" : "heyitsstevo",
        "-visible" : "true",
        "-version" : "6"
    },
    {
        "-id" : "29331497",
        "-uid" : "1899168",
        "-version" : "2",
        "-lon" : "144.9451088",
        "-timestamp" : "2014-10-25T03:36:51Z",
        "-user" : "heyitsstevo",
        "-visible" : "true",
        "-changeset" : "26313303",
        "-lat" : "-37.601881"
    },
    {
        "-id" : "29331498",
        "-timestamp" : "2014-10-25T03:36:51Z",
        "-version" : "3",
        "-uid" : "1899168",
        "-user" : "heyitsstevo",
        "-visible" : "true",
        "-changeset" : "26313303",
        "-lat" : "-37.6011267",
        "-lon" : "144.9448575"
    },
    {
        "-lon" : "144.943302",
        "-id" : "29331499",
        "-timestamp" : "2011-11-23T03:21:40Z",
        "-user" : "melb_guy",
        "-version" : "9",
        "-uid" : "11111",
        "-visible" : "true",
        "-changeset" : "9916439",
        "-lat" : "-37.5983291"
    },
    {
        "-id" : "60648717",
        "-uid" : "46482",
        "-user" : "Zulu99",
        "-lat" : "-37.6796337",
        "-lon" : "144.9220639",
        "-timestamp" : "2009-12-12T21:29:36Z",
        "-visible" : "true",
        "-version" : "2",
        "-changeset" : "3358816"
    },
    {
        "-id" : "60648718",
        "-timestamp" : "2009-12-12T21:29:35Z",
        "-uid" : "46482",
        "-version" : "2",
        "-changeset" : "3358816",
        "-user" : "Zulu99",
        "-visible" : "true",
        "-lat" : "-37.6787103",
        "-lon" : "144.9224609"
    },
    {
        "-id" : "60648719",
        "-timestamp" : "2009-12-12T21:28:58Z",
        "-user" : "Leon K",
        "-version" : "2",
        "-changeset" : "3358816",
        "-uid" : "Zulu99",
        "-visible" : "true",
        "-lat" : "-37.677841",
        "-lon" : "144.9227344"
    }
]
}

如何返回具有" -user"的所有节点? =" Zulu99"并排除其他任何内容?

我尝试过以下查询,但它只返回它找到的第一个节点" Zulu99":

db.osm.find( { }, { node: {$elemMatch: {'-user': 'Zulu99'}}} )

2 个答案:

答案 0 :(得分:2)

您需要的是"aggregation"以及$map$setDifference运营商

db.collection.aggregate([ 
    { 
        "$match": { 
            "node.-user": "Zulu99", 
            "node.-lat": "-37.6787103" 
        }
    },
    { 
        "$project": { 
            "node": { 
                "$setDifference": [{ 
                    "$map": { 
                        "input": "$node",
                        "as": "n", 
                        "in": { 
                            "$cond": [
                                { "$eq": [ "$$n.-user", "Zulu99" ]}, 
                                "$$n", 
                                false 
                            ]
                        } 
                    }
                }, 
                [false]]
            }
        }
    }
])

从MongoDB 3.2,您可以使用$filter运算符

db.collection.aggregate([
    { 
        "$match":  { 
            "node.-user": "Zulu99",
            "node.-lat": "-37.6787103"
        }
    }, 
    { "$project": {
        "node": {
            "$filter": {
                "input": "$node",
                "as": "n",
                "cond": { "$eq": [ "$$node.n", "Zulu99" ] }
            }
        }
    }}
])

产生:

{
        "_id" : ObjectId("55acf6187d4c31475417fa62"),
        "node" : [
                {
                        "-id" : "60648717",
                        "-uid" : "46482",
                        "-user" : "Zulu99",
                        "-lat" : "-37.6796337",
                        "-lon" : "144.9220639",
                        "-timestamp" : "2009-12-12T21:29:36Z",
                        "-visible" : "true",
                        "-version" : "2",
                        "-changeset" : "3358816"
                },
                {
                        "-id" : "60648718",
                        "-timestamp" : "2009-12-12T21:29:35Z",
                        "-uid" : "46482",
                        "-version" : "2",
                        "-changeset" : "3358816",
                        "-user" : "Zulu99",
                        "-visible" : "true",
                        "-lat" : "-37.6787103",
                        "-lon" : "144.9224609"
                }
        ]
}

答案 1 :(得分:0)

如果您的文档数量超过aggregation $unwind会产生 Cartesian Product 问题,即每个数组对象都会创建多个文档,因此会创建速度慢的聚合查询,如果您想要避免此问题,请使用 $redact ,如下所示:

db.collectionName.aggregate({
  "$match": {
    "node.-user": "Zulu99"
  }
}, {
  "$redact": {
    "$cond": {
      "if": {
        "$eq": [{
          "$ifNull": ["$-user", "Zulu99"]
        }, "Zulu99"]
      },
      "then": "$$DESCEND",
      "else": "$$PRUNE"
    }
  }
}).pretty()

修改

如果您想要多个条件,请使用$cond$and这样的

db.collectionName.aggregate({
  "$match": {
    "node.-user": "Zulu99",
    "node.-lat": "-37.6787103"
  }
}, {
  "$redact": {
    "$cond": {
      "if": {
        "$and": [{
          "$eq": [{
            "$ifNull": ["$-user", "Zulu99"]
          }, "Zulu99"]
        }, {
          "$eq": [{
            "$ifNull": ["$-lat", "-37.6787103"]
          }, "-37.6787103"]
        }]
      },
      "then": "$$DESCEND",
      "else": "$$PRUNE"
    }
  }
}).pretty()

在上面的查询中,您可以lat检查是否等于-37.6787103,如果您想检查-lat and -lon$gt or $lt,那么首先您应该更改数据文档中lat and lon的类型String看起来像String to number,因此首先更改了数据类型node,然后使用了comparison operator

第二件事,如果你只想要匹配的group数组对象,那么在readact之后使用db.collectionName.aggregate({ "$match": { "node.-user": "Zulu99", "node.-lat": "-37.6787103" } }, { "$redact": { "$cond": { "if": { "$and": [{ "$eq": [{ "$ifNull": ["$-user", "Zulu99"] }, "Zulu99"] }, { "$eq": [{ "$ifNull": ["$-lat", "-37.6787103"] }, "-37.6787103"] }] }, "then": "$$DESCEND", "else": "$$PRUNE" } } }, { "$group": { "_id": "$_id", "node": { "$first": "$node" // use $first } } }).pretty() 就像这样:

gte and lte

新修改

如果您想查找db.collectionName.aggregate({ "$project": { "check": { "$setDifference": [{ "$map": { "input": "$node", "as": "node1", "in": { "$cond": { "if": { "$and": [{ "$and": [{ "$gte": ["$$node1.-lon", 100] }, { "$lte": ["$$node1.-lon", 150] }] }, { "$and": [{ "$gte": ["$$node1.-lat", -50] }, { "$lte": ["$$node1.-lat", -10] }] }] }, "then": "$$node1", "else": false } } } }, [false] ] } } }).pretty() 条件,请遵循以下汇总:

public static bool TrySafeGet<T>(IList<T> list, int index, out T value)
{
    value = default(T);

    if (list == null || index < 0 || index >= list.Count)
    {    
        return false;
    }

    value = list[index];
    return true;
}