如何通过Geowithin从mongodb获得匹配的子文档?

时间:2021-12-11 18:02:03

What I am trying to do here is that I want only those subdocument which is within the provided latitude and longitude but if only one subdocument inside my document matches and others do not it should only return me the document with that particular document. but it is returning me all subdocument too can someone you guys help me out. my document is like this

我在这里要做的是,我只想要那些在提供的纬度和经度范围内的子文档,但如果我的文档中只有一个子文档匹配而其他子文档不匹配,那么它应该只返回具有该特定文档的文档。但它也归还给我所有子文档也可以有人帮助我。我的文件是这样的

{
         "_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
                    ]
                },
            }
        ],
    },
   }

I am applying this query.

我正在应用此查询。

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"
            });
        }
    });

and i am trying to get data like this.

而我正在尝试获取这样的数据。

{
         "_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
                    ]
                },
            }
        ],
    },
   }

is it possible to get data like this.

是否有可能获得这样的数据。

2 个解决方案

#1


3  

In the case of what you are trying to do here, the far better option is to actually use the $geoNear aggregation pipeline stage to determine the "nearest" matches within your constraints instead. Notably your criteria actually asks for $geoWithin for a 7 mile radius by the application of the math applied. So this really is better expressed using $geoNear, and it's options actually allow you to do what you want.

对于您在此处尝试执行的操作,更好的选择是实际使用$ geoNear聚合管道阶段来确定约束中的“最近”匹配。值得注意的是,通过应用数学应用,您的标准实际上要求7英里半径的$ geoWithin。因此,使用$ 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.
})

This would produce a result that looks like this:

这会产生如下结果:

{
        "_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
                ]
        }
}

We are using two stages here in the aggregation pipeline, so to explain what each is actually doing:

我们在聚合管道中使用了两个阶段,因此要解释每个阶段实际上在做什么:

First the $geoNear performs the query given the location provided here in GeoJSON format for comparison within the "near" option, and this is of course the primary constraint. The "spherical" option is generally required for "2dsphere" indexes, and that is the type of index you actually want for your data. The "distanceField" is the other mandatory argument, and it specifies the name of the property which will actually record the distance from the queried point for the location the "document" was matched on.

首先,$ geoNear执行查询,给定此处以GeoJSON格式提供的位置,以便在“near”选项中进行比较,这当然是主要约束。 “2dsphere”索引通常需要“球形”选项,这是您实际需要的数据索引类型。 “distanceField”是另一个必需参数,它指定了属性的名称,该属性将实际记录与“文档”匹配位置的查询点之间的距离。

The other options are the parts that make this work for what you want to do here. Firstly there is the "distanceMultiplier", which is actually "optional" here as it simply governs the value which will be output in the property specified by "distanceField". The value we are using here will adjust the meters returned as the "distance" into miles, which is what you are generally looking at. This actually does not have any other impact on the rest of the options, but since the "distanceField" is mandatory, we want to show an "expected" numeric value.

其他选项是使这个工作适合您想要做的事情的部分。首先是“distanceMultiplier”,它实际上是“可选的”,因为它只是控制将在“distanceField”指定的属性中输出的值。我们在这里使用的值将调整返回的仪表作为“距离”进入英里,这是您通常看到的。这实际上对其余选项没有任何其他影响,但由于“distanceField”是必需的,我们希望显示“预期的”数值。

The next option is the other main "filter" to mimic your $geoWithin statement. The "maxDistance" option sets an upper limit on "how far away" a matched location can be. In this case we give it 7 for the miles where we multiply by 1609.34 which is how many meters are in a mile. Note the "distanceMultiplier" has no effect on this number, so any "conversion" must be done here as well.

下一个选项是模仿你的$ geoWithin语句的另一个主“过滤器”。 “maxDistance”选项设置匹配位置“距离多远”的上限。在这种情况下,我们给它7英里乘以1609.34英里,这是一英里多少米。请注意,“distanceMultiplier”对此数字没有影响,因此任何“转换”也必须在此处完成。

The final option here is the "includeLocs", which is actually the most important option here aside from the distance constraint. This is the actual part that tells us the "location data" which was actually used for the "nearest match" from the array of locations contained in the document. What is defined here is of course the property which will be used to store this data in the documents returned from this pipeline stage. You can see the additional "location" property added to each document reflecting this.

这里的最后一个选项是“includeLocs”,除了距离约束之外,这里实际上是最重要的选项。这是告诉我们“位置数据”的实际部分,它实际上用于文档中包含的位置数组中的“最接近匹配”。这里定义的当然是用于将此数据存储在从此管道阶段返回的文档中的属性。您可以看到添加到每个文档的附加“位置”属性反映了这一点。

So that pipeline stage has actually identified the matching "location" data, but this does not actually identify which array member was actually matched, explicitly. So in order to actually return the information for the specific array member we can use $filter for the comparison.

因此,管道阶段实际上已经识别出匹配的“位置”数据,但这实际上并没有明确地识别哪个阵列成员实际匹配。因此,为了实际返回特定数组成员的信息,我们可以使用$ filter进行比较。

The operation of course is a simple comparison of the "matched location" to the actual "location" data of each array member. Since there will only ever be one match, you could alternately use things like $indexOfArray and $arrayElemAt to do the comparison and extract only the "single" result, but $filter is generally the most self explanatory operation that is easy to understand.

当然,操作是将“匹配位置”与每个阵列成员的实际“位置”数据进行简单比较。由于只有一个匹配,你可以交替使用$ indexOfArray和$ arrayElemAt之类的东西进行比较,只提取“单个”结果,但$ filter通常是最容易理解的最自我解释的操作。


The whole point of the restriction on the radius can be demonstrated by a few short changes to the conditions. So if we move the location away slightly:

对半径的限制的全部要点可以通过对条件的一些短暂改变来证明。因此,如果我们稍微移开该位置:

  { "$geoNear": {
    "near": {
      "type": "Point",
      "coordinates": [76.7786787, 30.6352527]    // <-- different location
    },
    "spherical": true,
    "distanceField": "distance",
    "distanceMultiplier": 0.000621371,
    "maxDistance": 7 * 1609.34,
    "includeLocs": "location"
  }},

This is still within the radius as reported within the output as specified for "distanceField":

这仍然在输出中报告的半径范围内,为“distanceField”指定:

 "distance" : 6.917030204982402,

But if you change that radius to be less than the reported number:

但是,如果您将该半径更改为小于报告的数字:

  { "$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"
  }},

Then the query would return neither of the documents presented in the question. Thus you can see how this setting governs the same boundaries as is implemented with the $geoWithin query, and of course we can now identify the matched sub-document.

然后查询将不返回问题中提供的文档。因此,您可以看到此设置如何控制与使用$ geoWithin查询实现的边界相同的边界,当然我们现在可以识别匹配的子文档。


Multiple matches

As a final note on the subject we can see how the "includeLocs" option can be used to identify the matching entry for a location within an array of a parent document. Whilst this should suit the use case here, the clear limitation is in matching mutliple locations within a range.

作为关于该主题的最后一点,我们可以看到“includeLocs”选项如何用于标识父文档数组中位置的匹配条目。虽然这应该适合这里的用例,但明显的限制是匹配范围内的多个位置。

So "multiple" matches is simply beyond the scope of the $geoNear or other geospatial operations with MongoDB. An alternate case would be instead $unwind the array content after the intial $geoNear and then the $geoWithin stage in order to "filter" those multiple matches:

因此,“多个”匹配超出了MongoDB的$ geoNear或其他地理空间操作的范围。另一种情况是,在初始$ 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.
})

It's probably better to actually use the $geoNear stage here, and we really just do the same thing without needing the "includeLocs" option. However if you really want to then there is nothing wrong with simply using the $geoWithin on either side of the $unwind stage:

实际上在这里实际使用$ geoNear阶段可能更好,我们真的只需要做同样的事情而不需要“includeLocs”选项。但是,如果你真的想要那么在$ unwind阶段的任何一侧使用$ geoWithin都没有错:

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.
})

The reason this is okay is because whilst $geoWithin works most "optimally" when it can actually use the geospatial index defined on the collection, it actually does not require the index in order to return results.

这是正确的原因是因为虽然$ geoWithin在实际上可以使用在集合上定义的地理空间索引时最“最优”地工作,但它实际上不需要索引来返回结果。

Hence in either case after the "initial query" returns the "document" which contains at least one match for the condition, we simply $unwind the array content and then apply the same constraints all over again to filter out those array entries, now as documents. If you want the "array" to be returned, then you can always $group and $push the elements back into array form.

因此,在“初始查询”返回包含至少一个条件匹配的“文档”之后的任何一种情况下,我们只需展开数组内容然后再次应用相同的约束来过滤掉那些数组条目,现在文档。如果你想要返回“数组”,那么你总是可以$ group和$将元素推回到数组形式。

By contrast the $geoNear pipeline stage must be used as the very first pipeline stage only. That is the only place it can use an index, and therefore it is not possible to use it at later stages. But of course the "nearest distance" information is probably useful to you and therefore worthwhile actually including within the query results and conditions.

相比之下,$ geoNear管道阶段必须仅用作第一个管道阶段。这是唯一可以使用索引的地方,因此无法在以后阶段使用它。但是,“最近距离”信息当然可能对您有用,因此实际上包括在查询结果和条件中是值得的。

#2


1  

User.aggregate([
        {
            path: '$parking_space',
            preserveNullAndEmptyArrays: true
        },
        { $geoNear: {
          near: { type: 'Point', 'parking_space.location.coordinates': [76.7786787, 30.7352527] },
          distanceField: 'dist',
          maxDistance: 7 / 3963.2,
          spherical: true
        } },
])

#1


3  

In the case of what you are trying to do here, the far better option is to actually use the $geoNear aggregation pipeline stage to determine the "nearest" matches within your constraints instead. Notably your criteria actually asks for $geoWithin for a 7 mile radius by the application of the math applied. So this really is better expressed using $geoNear, and it's options actually allow you to do what you want.

对于您在此处尝试执行的操作,更好的选择是实际使用$ geoNear聚合管道阶段来确定约束中的“最近”匹配。值得注意的是,通过应用数学应用,您的标准实际上要求7英里半径的$ geoWithin。因此,使用$ 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.
})

This would produce a result that looks like this:

这会产生如下结果:

{
        "_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
                ]
        }
}

We are using two stages here in the aggregation pipeline, so to explain what each is actually doing:

我们在聚合管道中使用了两个阶段,因此要解释每个阶段实际上在做什么:

First the $geoNear performs the query given the location provided here in GeoJSON format for comparison within the "near" option, and this is of course the primary constraint. The "spherical" option is generally required for "2dsphere" indexes, and that is the type of index you actually want for your data. The "distanceField" is the other mandatory argument, and it specifies the name of the property which will actually record the distance from the queried point for the location the "document" was matched on.

首先,$ geoNear执行查询,给定此处以GeoJSON格式提供的位置,以便在“near”选项中进行比较,这当然是主要约束。 “2dsphere”索引通常需要“球形”选项,这是您实际需要的数据索引类型。 “distanceField”是另一个必需参数,它指定了属性的名称,该属性将实际记录与“文档”匹配位置的查询点之间的距离。

The other options are the parts that make this work for what you want to do here. Firstly there is the "distanceMultiplier", which is actually "optional" here as it simply governs the value which will be output in the property specified by "distanceField". The value we are using here will adjust the meters returned as the "distance" into miles, which is what you are generally looking at. This actually does not have any other impact on the rest of the options, but since the "distanceField" is mandatory, we want to show an "expected" numeric value.

其他选项是使这个工作适合您想要做的事情的部分。首先是“distanceMultiplier”,它实际上是“可选的”,因为它只是控制将在“distanceField”指定的属性中输出的值。我们在这里使用的值将调整返回的仪表作为“距离”进入英里,这是您通常看到的。这实际上对其余选项没有任何其他影响,但由于“distanceField”是必需的,我们希望显示“预期的”数值。

The next option is the other main "filter" to mimic your $geoWithin statement. The "maxDistance" option sets an upper limit on "how far away" a matched location can be. In this case we give it 7 for the miles where we multiply by 1609.34 which is how many meters are in a mile. Note the "distanceMultiplier" has no effect on this number, so any "conversion" must be done here as well.

下一个选项是模仿你的$ geoWithin语句的另一个主“过滤器”。 “maxDistance”选项设置匹配位置“距离多远”的上限。在这种情况下,我们给它7英里乘以1609.34英里,这是一英里多少米。请注意,“distanceMultiplier”对此数字没有影响,因此任何“转换”也必须在此处完成。

The final option here is the "includeLocs", which is actually the most important option here aside from the distance constraint. This is the actual part that tells us the "location data" which was actually used for the "nearest match" from the array of locations contained in the document. What is defined here is of course the property which will be used to store this data in the documents returned from this pipeline stage. You can see the additional "location" property added to each document reflecting this.

这里的最后一个选项是“includeLocs”,除了距离约束之外,这里实际上是最重要的选项。这是告诉我们“位置数据”的实际部分,它实际上用于文档中包含的位置数组中的“最接近匹配”。这里定义的当然是用于将此数据存储在从此管道阶段返回的文档中的属性。您可以看到添加到每个文档的附加“位置”属性反映了这一点。

So that pipeline stage has actually identified the matching "location" data, but this does not actually identify which array member was actually matched, explicitly. So in order to actually return the information for the specific array member we can use $filter for the comparison.

因此,管道阶段实际上已经识别出匹配的“位置”数据,但这实际上并没有明确地识别哪个阵列成员实际匹配。因此,为了实际返回特定数组成员的信息,我们可以使用$ filter进行比较。

The operation of course is a simple comparison of the "matched location" to the actual "location" data of each array member. Since there will only ever be one match, you could alternately use things like $indexOfArray and $arrayElemAt to do the comparison and extract only the "single" result, but $filter is generally the most self explanatory operation that is easy to understand.

当然,操作是将“匹配位置”与每个阵列成员的实际“位置”数据进行简单比较。由于只有一个匹配,你可以交替使用$ indexOfArray和$ arrayElemAt之类的东西进行比较,只提取“单个”结果,但$ filter通常是最容易理解的最自我解释的操作。


The whole point of the restriction on the radius can be demonstrated by a few short changes to the conditions. So if we move the location away slightly:

对半径的限制的全部要点可以通过对条件的一些短暂改变来证明。因此,如果我们稍微移开该位置:

  { "$geoNear": {
    "near": {
      "type": "Point",
      "coordinates": [76.7786787, 30.6352527]    // <-- different location
    },
    "spherical": true,
    "distanceField": "distance",
    "distanceMultiplier": 0.000621371,
    "maxDistance": 7 * 1609.34,
    "includeLocs": "location"
  }},

This is still within the radius as reported within the output as specified for "distanceField":

这仍然在输出中报告的半径范围内,为“distanceField”指定:

 "distance" : 6.917030204982402,

But if you change that radius to be less than the reported number:

但是,如果您将该半径更改为小于报告的数字:

  { "$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"
  }},

Then the query would return neither of the documents presented in the question. Thus you can see how this setting governs the same boundaries as is implemented with the $geoWithin query, and of course we can now identify the matched sub-document.

然后查询将不返回问题中提供的文档。因此,您可以看到此设置如何控制与使用$ geoWithin查询实现的边界相同的边界,当然我们现在可以识别匹配的子文档。


Multiple matches

As a final note on the subject we can see how the "includeLocs" option can be used to identify the matching entry for a location within an array of a parent document. Whilst this should suit the use case here, the clear limitation is in matching mutliple locations within a range.

作为关于该主题的最后一点,我们可以看到“includeLocs”选项如何用于标识父文档数组中位置的匹配条目。虽然这应该适合这里的用例,但明显的限制是匹配范围内的多个位置。

So "multiple" matches is simply beyond the scope of the $geoNear or other geospatial operations with MongoDB. An alternate case would be instead $unwind the array content after the intial $geoNear and then the $geoWithin stage in order to "filter" those multiple matches:

因此,“多个”匹配超出了MongoDB的$ geoNear或其他地理空间操作的范围。另一种情况是,在初始$ 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.
})

It's probably better to actually use the $geoNear stage here, and we really just do the same thing without needing the "includeLocs" option. However if you really want to then there is nothing wrong with simply using the $geoWithin on either side of the $unwind stage:

实际上在这里实际使用$ geoNear阶段可能更好,我们真的只需要做同样的事情而不需要“includeLocs”选项。但是,如果你真的想要那么在$ unwind阶段的任何一侧使用$ geoWithin都没有错:

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.
})

The reason this is okay is because whilst $geoWithin works most "optimally" when it can actually use the geospatial index defined on the collection, it actually does not require the index in order to return results.

这是正确的原因是因为虽然$ geoWithin在实际上可以使用在集合上定义的地理空间索引时最“最优”地工作,但它实际上不需要索引来返回结果。

Hence in either case after the "initial query" returns the "document" which contains at least one match for the condition, we simply $unwind the array content and then apply the same constraints all over again to filter out those array entries, now as documents. If you want the "array" to be returned, then you can always $group and $push the elements back into array form.

因此,在“初始查询”返回包含至少一个条件匹配的“文档”之后的任何一种情况下,我们只需展开数组内容然后再次应用相同的约束来过滤掉那些数组条目,现在文档。如果你想要返回“数组”,那么你总是可以$ group和$将元素推回到数组形式。

By contrast the $geoNear pipeline stage must be used as the very first pipeline stage only. That is the only place it can use an index, and therefore it is not possible to use it at later stages. But of course the "nearest distance" information is probably useful to you and therefore worthwhile actually including within the query results and conditions.

相比之下,$ geoNear管道阶段必须仅用作第一个管道阶段。这是唯一可以使用索引的地方,因此无法在以后阶段使用它。但是,“最近距离”信息当然可能对您有用,因此实际上包括在查询结果和条件中是值得的。

#2


1  

User.aggregate([
        {
            path: '$parking_space',
            preserveNullAndEmptyArrays: true
        },
        { $geoNear: {
          near: { type: 'Point', 'parking_space.location.coordinates': [76.7786787, 30.7352527] },
          distanceField: 'dist',
          maxDistance: 7 / 3963.2,
          spherical: true
        } },
])