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}
]