我有两个集合成员和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/