在Mongoose附近使用elemMatch

时间:2014-04-08 07:38:16

标签: node.js mongodb mongoose

我在商店的集合中搜索。商店有嵌入式商店和地点。我的目标是返回在地理位置附近有商店的商店,并且只返回那个地点的商店。

我可以成功地将查询限制为仅使用' near'

返回商店在特定位置有一个商店

Store
  .where('isActive').equals(true)
  .where('outlets.location')
  .near({ center: [153.027117, -27.468515], maxDistance: 1000 / 6378137, spherical: true })
  .where('outlets.isActive').equals(true)
  .where('products.productType').equals('53433f1f3e02e39addde1954')
  .where('products.isActive').equals(true)
  .select('name outlets')
  .select({'products': {$elemMatch: {'isActive': true, 'productType': '53433f1f3e02e39addde1954'}}})
  .select('name outlets')
  .execQ()
  .then(function (results) {
    console.log(results);
  })
  .fail(function (err) {
    console.log(err);
  })
  .done();

我遇到的问题是商店文件会返回所有商店,而不仅仅是与地理位置匹配的商店。我尝试过使用elemMatch,就像我对产品一样;

  

。选择({' outlet':{$ elemMatch:{' location':{near:{center:[153.027117,-27.468515],maxDistance:10000/6378137,球形:true}}}}})

然而它返回一个空数组。可以在elemMatch子句中使用near运算符吗?我做错了吗?是否有更有效/更快/更好的方法来实现目标?

1 个答案:

答案 0 :(得分:1)

我看到你在这里想要做什么,但在这种设计中似乎存在一些缺陷。虽然不完全是您的文档结构,但我发现您正在尝试这样做:

{
    "_id" : ObjectId("5344badd519563414f23fdf8"),
    "store" : "Mine",
    "outlets" : [
            {
                    "name" : "somewhere",
                    "loc" : {
                            "type" : "Point",
                            "coordinates" : [
                                    150.975131,
                                    -33.8440366
                            ]
                    }
            },
            {
                    "name" : "else",
                    "loc" : {
                            "type" : "Point",
                            "coordinates" : [
                                    151.3651524,
                                    -33.8389783
                            ]
                    }
            }
    ]
}
{
    "_id" : ObjectId("5344be6f519563414f23fdf9"),
    "store" : "Another",
    "outlets" : [
            {
                    "name" : "else",
                    "loc" : {
                            "type" : "Point",
                            "coordinates" : [
                                    151.3651524,
                                    -33.8389783
                            ]
                    }
            },
            {
                    "name" : "somewhere",
                    "loc" : {
                            "type" : "Point",
                            "coordinates" : [
                                    150.975131,
                                    -33.8440366
                            ]
                    }
            }
    ]
}

所以基本上你似乎试图将出口位置嵌套在顶级文档中的数组中。

我所指的缺陷是,在设计上,任何类型的"附近"基于查询将返回多于1个结果。当你看到目的时,这似乎是合乎逻辑的。你当然可以修改它以限制结果" maxDistance"但一般来说它会超过1.

所以唯一的方法是.limit()将光标返回的结果发送到单个"最近的"响应。另请注意,对于某些操作,这些结果不一定是"排序"首先使用"最近的响应。

现在,由于这些结果实际上包含在文档的数组中,请记住.find()本身实际上并没有"过滤"数组的结果,当然文档将包含所有数组内容。

如果你试图"项目"使用位置$运算符,然后问题回落到原始点,因为没有单数实际匹配,因此无法返回"索引"匹配元素的值。如果您确实尝试过此操作,那么您将始终获得默认索引值0,因此只返回第一个元素。

如果那时你认为你可以跑去聚合,并试图实际上"去标准化"如果需要在任何聚合管道语句的第一个阶段使用索引,那么数组条目就会运气不好。

因此,对此的总结是,这样的嵌入条目不适合您需要在这些商店位置进行地理空间匹配的设计。这些地点在一个单独的收藏中更好:

{
    "_id" : ObjectId("5344bec7519563414f23fdfa"),
    "store": "Mine"
    "name" : "else",
    "loc" : {
            "type" : "Point",
            "coordinates" : [
                    151.3651524,
                    -33.8389783
            ]
    }
}
{
    "_id" : ObjectId("5344bed5519563414f23fdfb"),
    "store": "Mine"
    "name" : "somewhere",
    "loc" : {
            "type" : "Point",
            "coordinates" : [
                    150.975131,
                    -33.8440366
            ]
    }
}

这样就可以让你限制"结果到了最近的"通过将限制设置为1来匹配。您还可以包含任何必要的值,例如" store"用于过滤。如果需要,除了需要过滤之外,还可以包含其他信息,或者只是将ObjectId值放在原始对象的数组中,或者甚至可能对两个集合都重复。

但是,由于这些查询的本质不仅仅是返回1个匹配,因此您无法在嵌入式文档中使用它。因此,您的解决方案将需要对整体架构进行一些更改。