mongodb 循环管道 geoNear
mongodb loopup pipeline geoNear
我 运行 遇到了一个问题,我试图在查找中获取当前文档附近的一些文档。如果我手动输入 lon/lat,则以下查询将起作用,但尝试使用“let”中的任何内容时失败。如何在查找管道中引用 geoNear 中父文档的位置?
[
{
"$match":{
'assessed_improvement_value':{'$gt':500},
'sqft':{'$gt':500}
}
},
{
"$lookup":{
"from":"properties",
"let":{
'lon':{"$arrayElemAt":["$location.coordinates",0]},
'lat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$geoNear": {
"near": { "type": "Point", "coordinates": [ "$$lon" , "$$lat" ] },
"distanceField": "distance",
"spherical": true
}
},
{"$limit":10}
],
"as":"comps",
}
},
{"$limit":10}
]
更新
我发布的第一个方法实际上是一团糟。我现在想出了一个更清洁的解决方案。我希望这对以后的人有帮助
[
{
"$lookup":{
"from":"properties",
"let":{
'plon':{"$arrayElemAt":["$location.coordinates",0]},
'plat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$addFields":{
"distance":{
"$function":{
"body":"""
function(plonRad,platRad, lonRad, latRad) {
var R = 6373.0;
var dlon = lonRad - plonRad;
var dlat = latRad - platRad;
if((dlon == 0) || (dlat == 0)) {
return 0;
}
var a = Math.pow(Math.sin(dlat / 2),2)+ Math.cos(platRad) * Math.cos(latRad) * Math.pow(Math.sin(dlon / 2),2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var dist = R * c;
return dist*0.621371;
}
""",
"args":[
{"$toDouble":{"$degreesToRadians":"$$plon"}},
{"$toDouble":{"$degreesToRadians":"$$plat"}},
{"$toDouble":{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",0]}}},
{"$toDouble":{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",1]}}}],
"lang":"js"
}
}
}
},
{
"$match":{
"distance":{"$gt":0}
}
},
{"$sort":{"distance":1}},
{"$limit":20}
],
"as":"comps",
}
}
]
我想这是一个老错误,无论出于何种原因从未修复过。这感觉一团糟,但它是一个可行的解决方案。这将手动计算以英里为单位的距离。
[
{
"$match":{
'assessed_improvement_value':{'$gt':500},
'sqft':{'$gt':500}
}
},
{
"$lookup":{
"from":"properties",
"let":{
'lon':{"$arrayElemAt":["$location.coordinates",0]},
'lat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$addFields": {
'plonRad':{"$degreesToRadians":"$$lon"},
'platRad':{"$degreesToRadians":"$$lat"},
'lonRad':{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",0]}},
'latRad':{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",1]}},
}
},
{
'$addFields':{
"dlon":{
"$subtract":["$plonRad", "$lonRad"]
},
"dlat":{
"$subtract":["$platRad", "$latRad"]
},
}
},
{
"$addFields":{
'a':{
"$multiply":[
{
"$add":[
{
"$pow":[
{
"$sin":{
"$divide":["$dlat",2]
}
},
2
]
},
{
"$cos":"$platRad"
}
]
},
{
"$add":[
{
"$pow":[
{
"$sin":{
"$divide":["$dlon",2]
}
},
2
]
},
{
"$cos":"$latRad"
}
]
}
]
},
}
},
{
"$addFields":{
"c":{
"$atan2":[
{"$sqrt":"$a"},
{"$sqrt":{"$subtract":[1,"$a"]}}
]
}
}
},
{
"$addFields":{
"distance":{
"$divide":[
{"$multiply":[6373.0,"$c"]},
1609.34
]
}
}
},
{"$limit":10}
],
"as":"comps",
}
},
{"$limit":10}
]
我 运行 遇到了一个问题,我试图在查找中获取当前文档附近的一些文档。如果我手动输入 lon/lat,则以下查询将起作用,但尝试使用“let”中的任何内容时失败。如何在查找管道中引用 geoNear 中父文档的位置?
[
{
"$match":{
'assessed_improvement_value':{'$gt':500},
'sqft':{'$gt':500}
}
},
{
"$lookup":{
"from":"properties",
"let":{
'lon':{"$arrayElemAt":["$location.coordinates",0]},
'lat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$geoNear": {
"near": { "type": "Point", "coordinates": [ "$$lon" , "$$lat" ] },
"distanceField": "distance",
"spherical": true
}
},
{"$limit":10}
],
"as":"comps",
}
},
{"$limit":10}
]
更新 我发布的第一个方法实际上是一团糟。我现在想出了一个更清洁的解决方案。我希望这对以后的人有帮助
[
{
"$lookup":{
"from":"properties",
"let":{
'plon':{"$arrayElemAt":["$location.coordinates",0]},
'plat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$addFields":{
"distance":{
"$function":{
"body":"""
function(plonRad,platRad, lonRad, latRad) {
var R = 6373.0;
var dlon = lonRad - plonRad;
var dlat = latRad - platRad;
if((dlon == 0) || (dlat == 0)) {
return 0;
}
var a = Math.pow(Math.sin(dlat / 2),2)+ Math.cos(platRad) * Math.cos(latRad) * Math.pow(Math.sin(dlon / 2),2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var dist = R * c;
return dist*0.621371;
}
""",
"args":[
{"$toDouble":{"$degreesToRadians":"$$plon"}},
{"$toDouble":{"$degreesToRadians":"$$plat"}},
{"$toDouble":{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",0]}}},
{"$toDouble":{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",1]}}}],
"lang":"js"
}
}
}
},
{
"$match":{
"distance":{"$gt":0}
}
},
{"$sort":{"distance":1}},
{"$limit":20}
],
"as":"comps",
}
}
]
我想这是一个老错误,无论出于何种原因从未修复过。这感觉一团糟,但它是一个可行的解决方案。这将手动计算以英里为单位的距离。
[
{
"$match":{
'assessed_improvement_value':{'$gt':500},
'sqft':{'$gt':500}
}
},
{
"$lookup":{
"from":"properties",
"let":{
'lon':{"$arrayElemAt":["$location.coordinates",0]},
'lat':{"$arrayElemAt":["$location.coordinates",1]},
},
'pipeline': [
{
"$addFields": {
'plonRad':{"$degreesToRadians":"$$lon"},
'platRad':{"$degreesToRadians":"$$lat"},
'lonRad':{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",0]}},
'latRad':{"$degreesToRadians":{"$arrayElemAt":["$location.coordinates",1]}},
}
},
{
'$addFields':{
"dlon":{
"$subtract":["$plonRad", "$lonRad"]
},
"dlat":{
"$subtract":["$platRad", "$latRad"]
},
}
},
{
"$addFields":{
'a':{
"$multiply":[
{
"$add":[
{
"$pow":[
{
"$sin":{
"$divide":["$dlat",2]
}
},
2
]
},
{
"$cos":"$platRad"
}
]
},
{
"$add":[
{
"$pow":[
{
"$sin":{
"$divide":["$dlon",2]
}
},
2
]
},
{
"$cos":"$latRad"
}
]
}
]
},
}
},
{
"$addFields":{
"c":{
"$atan2":[
{"$sqrt":"$a"},
{"$sqrt":{"$subtract":[1,"$a"]}}
]
}
}
},
{
"$addFields":{
"distance":{
"$divide":[
{"$multiply":[6373.0,"$c"]},
1609.34
]
}
}
},
{"$limit":10}
],
"as":"comps",
}
},
{"$limit":10}
]