我有两个集合成员和mobileUserLocations—其中每个用户位置都保存为(可以是多个)userid作为foreign字段。
成员:

{
  _id: ObjectId("591553ffa4233a181506880c"),
  userName: "Test user"
}

移动用户位置:
{ _id: ObjectId("59156070a4233a1815068b6b"),
  userId: ObjectId("591553ffa4233a181506880c"),
  location: {type: "Point", coordinates: [76.9121, 10.2232]]},
  updatedOn: 2017-05-12T07:12:48.626Z,
  status: 1
},
{ _id: ObjectId("59156070a4233a1815068b6b"),
  userId: ObjectId("591553ffa4233a181506880c"),
  location: {type: "Point", coordinates: [76.8121, 10.1232]]},
  updatedOn: 2017-05-12T07:12:48.626Z,
  status: 1
}

我想得到半径范围内的成员,比如说5公里,参考一个特定的地理点,比如:[10.0132295,76.3630502](LAT,液化天然气格式)。
我试过这个:
collection.aggregate([
                                {$match: {_id: { $ne: options.accessToken.userId }},
                                { "$lookup": {
                                    "localField": "_id",
                                    "from": "MobileUserLocations",
                                    "foreignField": "userId",
                                    "as": "userLocInfo"
                                  }
                                },
                                {
                                    $project: {
                                        _id: 1,
                                        userLocInfo: {
                                           "$filter": {
                                                "input": "$userLocInfo",
                                                "as": "userLoc",
                                                "cond": {
                                                            "$eq": [ "$$userLoc.status", -1],
                                                       "$$userLoc.location": {"$geoWithin": {"$centerSphere": [[76.3630502, 10.0132295], 5 / 3963.2]}}
                                                        }
                                            }
                                        }
                                    }
                                },
                                {$unwind: "$userLocInfo"}

                      ]

但没有得到。如果我要从过滤器cond中删除$geoinfin,它会得到,否则不会得到。但如果我是个人查询收藏,我得到的结果。
有人知道这个问题吗?

最佳答案

这不起作用,因为$geoWithin不是“逻辑运算符”,但它是“查询运算符”,只能在使用$match的聚合管道中使用。幸运的是,这正是你想要的。尽管你还不明白为什么:

collection.aggregate([
  { "$match": {
    "_id": { "$ne": options.accessToken.userId }
  }},
  { "$lookup": {
    "localField": "_id",
    "from": "MobileUserLocations",
    "foreignField": "userId",
    "as": "userLocInfo"
  }},
  { "$unwind": "$userLocInfo" },
  { "$match": {
    "userLocInfo.status": -1,
    "userLocInfo.updatedOn": "2017-05-12T12:11:04.183Z",
    "userLocInfo.location": {
      "$geoWithin": {
        "$centerSphere": [[76.3630502, 10.0132295], 5 / 3963.2]
      }
    }
  }}
])

除了这是唯一可行的方法外,还有一个很好的理由。要理解,请查看"explain"输出:
    {
        "$lookup" : {
            "from" : "MobileUserLocations",
            "as" : "userLocInfo",
            "localField" : "_id",
            "foreignField" : "userId",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            },
            "matching" : {
                "$and" : [
                    {
                        "status" : {
                            "$eq" : -1.0
                        }
                    },
                    {
                        "updatedOn" : {
                            "$eq" : "2017-05-12T12:11:04.183Z"
                        }
                    },
                    {
                        "location" : {
                            "$geoWithin" : {
                                "$centerSphere" : [
                                    [
                                        76.3630502,
                                        10.0132295
                                    ],
                                    0.00126160678239806
                                ]
                            }
                        }
                    }
                ]
            }
        }
    }

这说明$unwind和随后的$match都被吸收到$lookup阶段。这意味着$geoWithin和其他条件实际上是在返回结果之前对外部集合执行的。
这就是$lookup处理可能违反16mb限制的结果连接的方式。这也是目前可以“过滤”连接结果的最有效方法。
所以这才是你真正想在这里做的。
根据你所问的数据,这个陈述:
db.members.aggregate([
  { "$lookup": {
    "localField": "_id",
    "from": "MobileUserLocations",
    "foreignField": "userId",
    "as": "userLocInfo"
  }},
  { "$unwind": "$userLocInfo" },
  { "$match": {
    "userLocInfo.location": {
      "$geoWithin": {
        "$centerSphere": [[76.9121, 10.2232], 5 / 3963.2]
      }
    }
  }}
])

过滤掉$lookup中与约束匹配的一个位置:
/* 1 */
{
    "_id" : ObjectId("591553ffa4233a181506880c"),
    "userName" : "Test user",
    "userLocInfo" : {
        "_id" : ObjectId("59c3c37359f55d64d6e30297"),
        "userId" : ObjectId("591553ffa4233a181506880c"),
        "location" : {
            "type" : "Point",
            "coordinates" : [
                76.9121,
                10.2232
            ]
        },
        "updatedOn" : ISODate("2017-05-12T07:12:48.626Z"),
        "status" : 1.0
    }
}

关于mongodb - 在$ lookup上使用外部集合的$ geowithin,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46341546/

10-11 21:12