附近的 MongoDB 查询

Posted

技术标签:

【中文标题】附近的 MongoDB 查询【英文标题】:MongoDB query nearby 【发布时间】:2020-12-03 01:29:54 【问题描述】:

我有一个收藏用户、餐馆、产品 我想查询用户将在他/她的应用程序中看到附近的餐厅(5 公里)isOpen: true 并显示每个餐厅的产品 isAvailable 和 isApproved = true 和 isArchived: false。

let kmToRadian = function(miles)
 var earthRadiusInMiles = 6378
 return miles / earthRadiusInMiles


var user = dbo.collection('users').findOne(_id: id)
var query = 
  "location": 
      $geoWithin: 
          $centerSphere: [ [22.222, 22.222], 5 / 6378.1] //sample coordinates
      
  



db.products.aggregate([
     
        $lookup:  
            from: "restaurants", 
            localField: "restaurants", 
            foreignField: "_id", 
            as: "restaurant" 
         
    ,
    
        $match : 
            "restaurant.isOpen": true,
            "isApproved": true,
            "isAvailable": true,
            "isArchived": false
        
    ,
    
        $project: 
            "restaurant.isOpen": 1,
            "isApproved": 1,
            "isAvailable": 1,
            "isArchived": 1,
            "name": 1
         
    
])

在这里,我得到产品 isAvailable、isApproved :true 和 isArchived false。现在,我想去附近 5 公里的餐厅。

收集用户

id: 1
name: "Robert"
location: Object
    type: "Point",
    coordinates: Array
     0: 11.111 //sample coordinates
     1: 11.111 //sample coordinates

id: 2
    name: "Jason"
    location: Object
        type: "Point",
        coordinates: Array
         0: 22.222 //sample coordinates
         1: 22.222 //sample coordinates

收藏餐厅

id: 1  
name: "Burger King"
location: Object
    type: "Point",
    coordinates: Array
       0: 11.111 //sample coordinates
       1: 11.111 //sample coordinates
isOpen: true

id: 2
name: "McDonald's"
location: Object
    type: "Point",
    coordinates: Array
       0: 22.222 //sample coordinates
       1: 22.222 //sample coordinates
isOpen: true

id: 3  
name: "Chick-fil-A"
location: Object
    type: "Point",
    coordinates: Array
       0: 22.333 //sample coordinates
       1: 22.333 //sample coordinates
isOpen: true

收藏品

id: 1
name: "Breakfast Whopper Jr."
price: "$1.29"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT+0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT+0800
isArchived: false
shop: ObjectId('1')

id: 2
name: "Big Mac"
price: "$4.35"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT+0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT+0800
isArchived: false
shop: ObjectId('2')

id: 3
name: "Spicy Chicken Sandwich"
price: "$3.29"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT+0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT+0800
isArchived: false
restaurant: ObjectId('3')

输出: 如果罗伯特在坐标 [22.222, 22.222]。 Robert 将看到麦当劳和 Chick-fil-A 餐厅,因为 isOpen: true。 显示他们的产品是巨无霸和辣鸡三明治,因为 isAvailable、isApproved: true 和 isArchived: false。

【问题讨论】:

@Minsky 嗨,我可以对在这种类型的查询中使用什么提出建议吗? db.products.aggregate([ $lookup: from: 'restaurants', localField: 'restaurants', foreignField: '_id', as: 'shop' , , $match: 'restaurant.isOpen': true ]) 接下来我想得到的是餐厅的可用产品和批准是真的,isArchived 是假的。我做对了吗? @明斯基 【参考方案1】:

不是一个答案,只是一些想法,你应该评估自己。以下管道:

    匹配isApproved:true, isAvailable:true, isArchived:true 所以它假设并建议使用这个索引:
db.products.createIndex(
  isAvailable: 1, isApproved: 1, isArchived: 1
)
    一旦文档数量被很好地缩小,查找应该不会花费那么长时间。只要使用foreignField:_id,这里就不需要索引,否则我会在该字段上创建一个索引。 $match isOpen:true 会很慢,但如果可行,稍后会提高性能。 pipeline in $lookup 可以帮助实现更好的性能,添加此索引(恕我直言)db.restaurants.createIndex( _id: 1, isOpen: 1 ) 我注释掉了我们在匹配中过滤掉的字段,因为我们知道值,并且可以设置,可能会提高性能(无法证明这一点)。 我们将 location 投射到其中,因为我们需要该字段 使用地理定位附近的东西,这几乎是正确的。这一步会比较慢,因为“geo”中没有索引,在这个查询中也不可能创建索引。
db.products.aggregate([
  
    $match: 
      "isApproved": true,
      "isAvailable": true,
      "isArchived": false
    
  ,
  
    $lookup: 
      from: "restaurants",
      foreignField: "_id",
      localField: "restaurant",
      as: "restaurant"
    
  ,
  
    $match: 
      "restaurant.isOpen": true
    
  ,
  
    $project: 
      "restaurant.isOpen": 1,
      //"isApproved": 1,
      //"isAvailable": 1,
      //"isArchived": 1,
      "name": 1,
      "restaurant.location": 1
    
  ,
  
    $match: 
      "restaurant.location": 
        $geoWithin: 
          $centerSphere: [
            [
              22.222,
              22.222
            ],
            5/6378.1] 
      
  
  
])

我必须说我不是专家,所以由你来测试和改进。另外,请仅包含 JSON 格式的文档,以便我们立即进行测试。我必须手动为LIVE VERSION 执行此操作。

(也很高兴记住,不是那么有用但快速且终止良好的东西比一个非常复杂的滞后应用程序更好。同样,你会发现它是如何工作的,我根本不是专家。)

【讨论】:

嗨,@Minsky 抱歉回复晚了。它没有返回我附近的餐厅。它返回一个空数组。

以上是关于附近的 MongoDB 查询的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB的地理位置索引

MongoDb中的“查询”和“命令”有啥区别

MongoDB $near 查询准确性问题

利用MongoDB进行地理坐标查询

Mongodb:如何找出某个位置附近的所有文件?

Mongodb - 没有结果返回时性能不佳