我有两个集合成员和MobileUserLocations - 其中每个用户位置被保存(可以是多个)作为userId作为外来字段。
成员:
{
_id: ObjectId("591553ffa4233a181506880c"),
userName: "Test user"
}
MobileUserLocations:
{ _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,lng格式)。
我试过了:
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中删除$ geowithin,它就会得到,否则就没有了。但是,如果我个性化地查询集合,我就会得到结果。
任何人都可以知道这个问题吗?
答案 0 :(得分:1)
这不起作用,因为$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
}
}