聚合$查找几何值

时间:2016-03-22 22:08:22

标签: mongodb mongodb-query aggregation-framework

我想在2个集合中进行$ lookup查询,其中第1个集合有单个点,第2个集合中有多边形...现在我想查询多边形内的所有点并从第1个集合构建平均值

我的实际汇总:

    'aggregation': {
        'pipeline': [
            # must match the field location from my first collection
            { "$match": {
                 "location" : "$loc" 
            } },

            # lookup to join location from 1st collection and geometry from 2nd collection
            { "$lookup": { 
                 "from": "polygons", 
                 "localField": "location", 
                 "foreignField": "geometry", 
                 "as": "join" } },

            # output grouped
            { "$group": { 
                "_id": "Average", 
                "Geometry": "$join.geometry" ,
                "AvgVal": { "$avg": "$myVal" }  , 
            "count": {"$sum": 1} } },
        ]
    }

我希望任何人都能理解我的意思; - )

编辑: 文件1:

{ id: "ABC", location: {type: "point", coordinates: [0,1]}, myVal: 1 },
{ id: "DEF", location: {type: "point", coordinates: [2,3]}, myVal: 2 }
{ id: "GHI", location: {type: "point", coordinates: [9,8]}, myVal: 3 }
{ id: "JKL", location: {type: "point", coordinates: [7,6]}, myVal: 4 }
{ id: "MNO", location: {type: "point", coordinates: [5,4]}, myVal: 5 }

文件2:

{ id: "Vienna Part1", geometry: {type: "polygon", coordinates: [[[0,1],[1,2],[2,3],[0,1]]] } },
{ id: "Vienna Part2", geometry: {type: "polygon", coordinates: [[[9,8],[7,6],[5,4],[9,8]]] } },

现在我发送一个带有多边形的查询(我的屏幕上的地图):$ geoIntersect polygon .. [0,1] ... [9,8]

预期:

{ id: "Vienna Part1", AvgVal: 1.5, geometry: {type: "polygon", coordinates: [[[0,1],[1,2],[2,3],[0,1]]] }
{ id: "Vienna Part2", AvgVal: 4, geometry: {type: "polygon", coordinates: [[[9,8],[7,6],[5,4],[9,8]]] }

LG 哈拉尔德

1 个答案:

答案 0 :(得分:2)

您似乎并不理解$lookup的概念是,对于要在查找中“匹配”的字段,它必须具有相同的数据。由于一个文档中包含的数据是以“多边形”表示法在数组中“双重嵌套”,因此需要$unwind数组内容“两次”以获得“匹配”。

作为一个整体的例子,让我们用你的“点”文档创建一个集合:

db.geo1.insertMany([
  { _id: "ABC", location: {type: "point", coordinates: [0,1]}, myVal: 1 },
  { _id: "DEF", location: {type: "point", coordinates: [2,3]}, myVal: 2 },
  { _id: "GHI", location: {type: "point", coordinates: [9,8]}, myVal: 3 },
  { _id: "JKL", location: {type: "point", coordinates: [7,6]}, myVal: 4 },
  { _id: "MNO", location: {type: "point", coordinates: [5,4]}, myVal: 5 }
])

另一个包括“多边形”文件,故意包括一个不匹配的文件:

db.geo2.insertMany([
  { _id: "Vienna Part1", geometry: {type: "polygon", coordinates: [[[0,1],[1,2],[2,3],[0,1]]] } },
  { _id: "Vienna Part2", geometry: {type: "polygon", coordinates: [[[9,8],[7,6],[5,4],[9,8]]] } },
  { _id: "Vienna Part3", geometry: {type: "polygon", coordinates: [[[10,1],[10,3],[3,10],[10,1]]] } }
])

为了检查geo2集合中geo1中通过相同点坐标“相交”的项目,您必须执行以下操作:

db.geo2.aggregate([
  { "$unwind": "$geometry.coordinates" },
  { "$unwind": "$geometry.coordinates" },
  { "$lookup": {
    "from": "geo1",
    "localField": "geometry.coordinates",
    "foreignField": "location.coordinates",
    "as": "geo1"
  }},
  { "$group": {
    "_id": "$_id",
    "coordinates": {
      "$push": "$geometry.coordinates"
    },
    "matches": {
      "$push": { "$ne": [ "$geo1", [] ] }
    }
  }},
  { "$redact": {
    "$cond": {
      "if": { "$anyElementTrue": "$matches" },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$project" : {
    "geometry": {
      "type": { "$literal": "polygon" },
      "coordinates": ["$coordinates"]
    }
  }},
  { "$sort": { "_id": 1 } }
])

所以第一件事是双$unwind来从数组中获取“点”数据。然后你可以做$lookup

{ "_id" : "Vienna Part1", "geometry" : { "type" : "polygon", "coordinates" : [ 0, 1 ] }, "geo1" : [ { "_id" : "ABC", "location" : { "type" : "point", "coordinates" : [ 0, 1 ] }, "myVal" : 1 } ] }
{ "_id" : "Vienna Part1", "geometry" : { "type" : "polygon", "coordinates" : [ 1, 2 ] }, "geo1" : [ ] }
{ "_id" : "Vienna Part1", "geometry" : { "type" : "polygon", "coordinates" : [ 2, 3 ] }, "geo1" : [ { "_id" : "DEF", "location" : { "type" : "point", "coordinates" : [ 2, 3 ] }, "myVal" : 2 } ] }
{ "_id" : "Vienna Part1", "geometry" : { "type" : "polygon", "coordinates" : [ 0, 1 ] }, "geo1" : [ { "_id" : "ABC", "location" : { "type" : "point", "coordinates" : [ 0, 1 ] }, "myVal" : 1 } ] }
{ "_id" : "Vienna Part2", "geometry" : { "type" : "polygon", "coordinates" : [ 9, 8 ] }, "geo1" : [ { "_id" : "GHI", "location" : { "type" : "point", "coordinates" : [ 9, 8 ] }, "myVal" : 3 } ] }
{ "_id" : "Vienna Part2", "geometry" : { "type" : "polygon", "coordinates" : [ 7, 6 ] }, "geo1" : [ { "_id" : "JKL", "location" : { "type" : "point", "coordinates" : [ 7, 6 ] }, "myVal" : 4 } ] }
{ "_id" : "Vienna Part2", "geometry" : { "type" : "polygon", "coordinates" : [ 5, 4 ] }, "geo1" : [ { "_id" : "MNO", "location" : { "type" : "point", "coordinates" : [ 5, 4 ] }, "myVal" : 5 } ] }
{ "_id" : "Vienna Part2", "geometry" : { "type" : "polygon", "coordinates" : [ 9, 8 ] }, "geo1" : [ { "_id" : "GHI", "location" : { "type" : "point", "coordinates" : [ 9, 8 ] }, "myVal" : 3 } ] }
{ "_id" : "Vienna Part3", "geometry" : { "type" : "polygon", "coordinates" : [ 10, 1 ] }, "geo1" : [ ] }
{ "_id" : "Vienna Part3", "geometry" : { "type" : "polygon", "coordinates" : [ 10, 3 ] }, "geo1" : [ ] }
{ "_id" : "Vienna Part3", "geometry" : { "type" : "polygon", "coordinates" : [ 3, 10 ] }, "geo1" : [ ] }
{ "_id" : "Vienna Part3", "geometry" : { "type" : "polygon", "coordinates" : [ 10, 1 ] }, "geo1" : [ ] }

结果数据显示文档中新数组元素geo1"geo1"集合中的“匹配”元素。这是一种“左连接”,所以有一个包含任何匹配的数组或一个空数组。

您的下一点是我们希望$group返回更像原始文档表单的内容,在这里我们测试$lookup的结果是否产生了一个空数组。这意味着在其他集合中“找不到”相应的文档:

{ 
    "_id" : "Vienna Part3",
    "coordinates" : [ [ 10, 1 ], [ 10, 3 ], [ 3, 10 ], [ 10, 1 ] ],
    "matches" : [ false, false, false, false ]
}
{ 
    "_id" : "Vienna Part2",
    "coordinates" : [ [ 9, 8 ], [ 7, 6 ], [ 5, 4 ], [ 9, 8 ] ],
    "matches" : [ true, true, true, true ]
}
{ 
    "_id" : "Vienna Part1", 
    "coordinates" : [ [ 0, 1 ], [ 1, 2 ], [ 2, 3 ], [ 0, 1 ] ],
    "matches" : [ true, false, true, true ]
}

您应该看到的是,其中一个文档的结果为"matches"数组,其中每个元素都为false。这对于以下$redact条件非常重要,该条件使用$anyElementTrue对该数组进行测试。

因此,在文档中看到所有元素都为false的数组,这意味着这个特定点集合没有“交集”。因此,该文件将通过$$PRUNE被丢弃,其中包含“至少一个”true的其他文件将被保留。

唯一剩下的是一些小的化妆品转换,以回馈所需的结果:

{ 
    "_id" : "Vienna Part1", 
    "geometry": {
        "type": "polygon",
        "coordinates" : [[ [ 0, 1 ], [ 1, 2 ], [ 2, 3 ], [ 0, 1 ] ]]
    }
}
{ 
    "_id" : "Vienna Part2",
    "geometry": {
        "type": "polygon",
        "coordinates" : [[ [ 9, 8 ], [ 7, 6 ], [ 5, 4 ], [ 9, 8 ] ]]
    }
}

当然,不同的几何类型会使这个过程复杂化,但这仍然是基本过程。

  1. 为了$lookup,您必须将数据转换为与正在检查的目标收集字段相匹配的表单。

  2. 在“set”中查看结果时,您可以测试每个元素的逻辑结果,然后使用$anyElementTrue进行评估。这将告诉您是否匹配某些内容而不会破坏各个元素。

  3. 因此,与第一个条件一样,第二个条件确保包含与其他集合中的“所有”文档不匹配的点的"Vienna Part1"文档也匹配,因为“至少有一个“元素对匹配进行了true评估。

    这些是规则。所以我希望你现在能更好地理解它。