Pri*_*han 7 geospatial mongoose mongodb node.js mongodb-query
我在这里要做的是,我只想要那些在提供的纬度和经度范围内的子文档,但如果我的文档中只有一个子文档匹配而其他子文档不匹配,那么它应该只返回带有该特定文档的文档.但它也归还给我所有子文档也可以有人帮助我.我的文件是这样的
{
"_id": "5ae04fd45f104a5980cf7e0e",
"name": "Rehan",
"email": "rehan@gmail.com",
"status": true,
"created_at": "2018-04-25T09:52:20.266Z",
"parking_space": [
{
"_id": "5ae05dce5f104a5980cf7e0f",
"parking_name": "my space 1",
"restriction": "no",
"hourly_rate": "3",
"location": {
"type": "Point",
"coordinates": [
86.84470799999997,
42.7052881
]
},
},
{
"_id": "5ae06d4d5f104a5980cf7e52",
"parking_name": "my space 2",
"restriction": "no",
"hourly_rate": "6",
"location": {
"type": "Point",
"coordinates": [
76.7786787,
30.7352527
]
},
}
],
},
{
"_id": "5ae2f8148d51db4937b9df02",
"name": "nellima",
"email": "neel@gmail.com",
"status": true,
"created_at": "2018-04-27T10:14:44.598Z",
"parking_space": [
{
"_id": "5ae2f89d8d51db4937b9df04",
"parking_name": "my space 3",
"restriction": "no",
"hourly_rate": "60",
"location": {
"type": "Point",
"coordinates": [
76.7786787,
30.7352527
]
},
}
],
},
}
Run Code Online (Sandbox Code Playgroud)
我正在应用此查询.
User.find({
"parking_space.location": {
"$geoWithin": {
"$centerSphere": [
[76.7786787, 30.7352527], 7 / 3963.2
]
}
},
}, function(err, park_places) {
if (err) {
return res.send({
data: err,
status: false
});
} else {
return res.send({
data: park_places,
status: true,
msg: "Parking data according to location"
});
}
});
Run Code Online (Sandbox Code Playgroud)
而我正在尝试获取这样的数据.
{
"_id": "5ae04fd45f104a5980cf7e0e",
"name": "Rehan",
"email": "rehan@gmail.com",
"status": true,
"created_at": "2018-04-25T09:52:20.266Z",
"parking_space": [
{
"_id": "5ae06d4d5f104a5980cf7e52",
"parking_name": "my space 2",
"restriction": "no",
"hourly_rate": "6",
"location": {
"type": "Point",
"coordinates": [
76.7786787,
30.7352527
]
},
}
],
},
{
"_id": "5ae2f8148d51db4937b9df02",
"name": "nellima",
"email": "neel@gmail.com",
"status": true,
"created_at": "2018-04-27T10:14:44.598Z",
"parking_space": [
{
"_id": "5ae2f89d8d51db4937b9df04",
"parking_name": "my space 3",
"restriction": "no",
"hourly_rate": "60",
"location": {
"type": "Point",
"coordinates": [
76.7786787,
30.7352527
]
},
}
],
},
}
Run Code Online (Sandbox Code Playgroud)
是否有可能获得这样的数据.
对于您要在此处进行的操作,更好的选择是实际使用$geoNear
聚合管道阶段来确定约束内的“最近”匹配。值得注意的是你的实际标准询问$geoWithin
了酒店7英里范围应用由数学的应用。因此,使用确实可以更好地表达这一点$geoNear
,并且它的选项实际上允许您执行所需的操作。
User.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [76.7786787, 30.7352527]
},
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371,
"maxDistance": 7 * 1609.34,
"includeLocs": "location"
}},
{ "$addFields": {
"parking_space": {
"$filter": {
"input": "$parking_space",
"cond": {
"$eq": ["$location", "$$this.location"]
}
}
}
}}
],function(err,park_places) {
// rest of your code.
})
Run Code Online (Sandbox Code Playgroud)
这将产生如下结果:
{
"_id" : "5ae04fd45f104a5980cf7e0e",
"name" : "Rehan",
"email" : "rehan@gmail.com",
"status" : true,
"created_at" : "2018-04-25T09:52:20.266Z",
"parking_space" : [
{
"_id" : "5ae06d4d5f104a5980cf7e52",
"parking_name" : "my space 2",
"restriction" : "no",
"hourly_rate" : "6",
"location" : {
"type" : "Point",
"coordinates" : [
76.7786787,
30.7352527
]
}
}
],
"distance" : 0,
"location" : {
"type" : "Point",
"coordinates" : [
76.7786787,
30.7352527
]
}
}
{
"_id" : "5ae2f8148d51db4937b9df02",
"name" : "nellima",
"email" : "neel@gmail.com",
"status" : true,
"created_at" : "2018-04-27T10:14:44.598Z",
"parking_space" : [
{
"_id" : "5ae2f89d8d51db4937b9df04",
"parking_name" : "my space 3",
"restriction" : "no",
"hourly_rate" : "60",
"location" : {
"type" : "Point",
"coordinates" : [
76.7786787,
30.7352527
]
}
}
],
"distance" : 0,
"location" : {
"type" : "Point",
"coordinates" : [
76.7786787,
30.7352527
]
}
}
Run Code Online (Sandbox Code Playgroud)
我们在聚合管道中使用两个阶段,以便解释每个阶段的实际操作:
首先,$geoNear
在给定的GeoJSON格式位置下执行查询,以便在"near"
选项中进行比较,这当然是主要的约束条件。索引"spherical"
通常需要该选项"2dsphere"
,这是您实际需要的数据索引类型。该"distanceField"
是其他强制参数,并指定将实际记录从“文件”被匹配上的位置的查询点的距离属性的名称。
其他选项是使此功能适用于您要在此处执行的部分。首先是"distanceMultiplier"
,实际上是“可选”的,因为它仅控制将在所指定的属性中输出的值"distanceField"
。我们在此处使用的值将把作为“距离”返回的米数调整为miles,这就是您通常要查看的距离。实际上,这对其余选项没有任何其他影响,但是由于"distanceField"
是必需的,因此我们希望显示“期望的”数值。
下一个选项是另一个主要的“过滤器”,用于模仿您的$geoWithin
陈述。该"maxDistance"
选项设置了匹配位置可以“多远”的上限。在这种情况下,我们给它7
的里程,我们乘上1609.34
这是多少米都是在英里。请注意"distanceMultiplier"
,对此数字没有影响,因此任何“转换”也必须在此完成。
这里的最后一个选项是"includeLocs"
,这实际上是距离约束之外最重要的选项。这是告诉我们文档中包含的位置数组实际用于“最近匹配”的“位置数据”的实际部分。当然,这里定义的是将用于在此管道阶段返回的文档中存储此数据的属性。您可以看到"location"
添加到每个文档的其他属性反映了这一点。
因此,该管道阶段实际上已识别出匹配的"location"
数据,但这并没有明确识别出实际匹配了哪个数组成员。因此,为了实际返回特定数组成员的信息,我们可以将其$filter
用于比较。
当然,该操作是将“匹配位置”与每个数组成员的实际“位置”数据进行简单比较。由于将永远只有一个匹配项,因此您可以交替使用$indexOfArray
和$arrayElemAt
进行比较,并仅提取“单个”结果,但这$filter
通常是最容易理解的操作。
半径限制的整个要点都可以通过对条件的一些简短更改来证明。因此,如果我们将位置稍微移开:
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [76.7786787, 30.6352527] // <-- different location
},
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371,
"maxDistance": 7 * 1609.34,
"includeLocs": "location"
}},
Run Code Online (Sandbox Code Playgroud)
它仍然在输出中报告的半径范围内,如以下指定"distanceField"
:
"distance" : 6.917030204982402,
Run Code Online (Sandbox Code Playgroud)
但是,如果您将该半径更改为小于报告的数字:
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [76.7786787, 30.6352527] // <-- different location
},
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371,
"maxDistance": 6.91 * 1609.34, // <--- smaller radius
"includeLocs": "location"
}},
Run Code Online (Sandbox Code Playgroud)
然后查询将不返回问题中显示的任何文档。因此,您可以看到此设置如何控制与$geoWithin
查询实现的边界相同的边界,当然,我们现在可以识别匹配的子文档。
作为对该主题的最后注解,我们可以看到如何使用该"includeLocs"
选项来标识父文档数组中某个位置的匹配条目。尽管这应该适合此处的用例,但明显的限制是在一定范围内匹配多个位置。
因此,“多个”匹配完全超出了$geoNear
MongoDB或其他地理空间操作的范围。另一种情况是,$unwind
将数组内容放在初始位置之后$geoNear
,然后是$geoWithin
阶段,以便“过滤”这些多个匹配项:
User.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [76.7786787, 30.7352527]
},
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371,
"maxDistance": 7 * 1609.34,
}},
{ "$unwind": "$parking_space" },
{ "$match": {
"parking_space.location": {
"$geoWithin": {
"$centerSphere": [
[76.7786787, 30.7352527], 7 / 3963.2
]
}
}
}}
],function(err,park_places) {
// rest of your code.
})
Run Code Online (Sandbox Code Playgroud)
在$geoNear
这里实际使用舞台可能会更好,并且我们实际上只是在做相同的事情而无需"includeLocs"
选择。但是,如果您确实要这样做,那么只需$geoWithin
在$unwind
舞台的任一侧使用,就没有错:
User.aggregate([
{ "$match": {
"parking_space.location": {
"$geoWithin": {
"$centerSphere": [
[76.7786787, 30.7352527], 7 / 3963.2
]
}
}
}}
{ "$unwind": "$parking_space" },
{ "$match": {
"parking_space.location": {
"$geoWithin": {
"$centerSphere": [
[76.7786787, 30.7352527], 7 / 3963.2
]
}
}
}}
],function(err,park_places) {
// rest of your code.
})
Run Code Online (Sandbox Code Playgroud)
可以这样做的原因是,尽管当它实际上可以使用在集合上定义的地理空间索引时,它$geoWithin
最“最佳”地工作,但实际上它不需要索引才能返回结果。
因此,无论哪种情况,在“初始查询”返回包含至少一个条件匹配项的“文档”之后,我们简单地$unwind
处理数组内容,然后再次应用相同的约束条件以过滤出那些数组条目,现在称为文档。如果您希望返回“数组”,则可以始终将元素$group
和$push
数组重新组合成数组。
相反,$geoNear
流水线阶段必须仅用作第一个流水线阶段。那是它唯一可以使用索引的地方,因此不可能在以后的阶段使用它。但是当然,“最近距离”信息可能对您有用,因此值得在查询结果和条件中包括在内。
归档时间: |
|
查看次数: |
564 次 |
最近记录: |