MongoDB - 查询难题 - 文档引用或子文档

时间:2015-04-27 19:28:28

标签: javascript node.js mongodb mongoose odm

我遇到了一些我存储在MongoDB中的数据的问题(注意:我使用的是mongoose作为ODM)。我有两个模式:

mongoose.model('Buyer',{
  credit: Number,
})

mongoose.model('Item',{
  bid: Number,
  location: { type: [Number], index: '2d' }
})

买方/物品将拥有父/子关联,并具有一对多的关系。我知道我可以将要嵌入子项的项目设置为买方文档我可以创建两个单独的文档,其中对象id引用彼此。

我面临的问题是,我需要查询项目哪里的出价低于买方的信用,还要哪里的位置接近某个地理坐标

为了满足第一个标准,似乎我应该将Items作为一个子块嵌入,以便我可以比较这两个数字。但是,为了将位置与geoNear查询进行比较,分离文档似乎更好,否则,我无法在每个子文档上执行geoNear。

有什么方法可以对这些数据执行这两项任务?如果是这样,我应该如何构建我的数据?如果没有,有没有办法可以执行一个查询,然后对第一个查询的结果进行第二次查询?

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

还有另一个选项(除了嵌入和规范化)用于在mongodb中存储层次结构,即将它们存储为tree structures。在这种情况下,您可以将买家和物品存储在单独的文档中,但存储在同一个集合中。每个Item文档都需要一个指向其Buyer(父)文档的字段,每个Buyer文档的父字段都将设置为null。我链接的文档解释了您可以选择的几种实现。

答案 1 :(得分:2)

如果您的项目存储在两个单独的集合中,那么最佳选项将编写您自己的函数并使用mongoose.connection.db.eval('some code...');进行调用。在这种情况下,您可以在服务器端执行高级逻辑。

你可以这样写:

var allNearItems = db.Items.find(
    { location: {
        $near: {
            $geometry: {
              type: "Point" ,
              coordinates: [ <longitude> , <latitude> ]
            },
            $maxDistance: 100
        }
    }
}); 
var res = [];
allNearItems.forEach(function(item){
    var buyer = db.Buyers.find({ id: item.buyerId })[0];
    if (!buyer) continue;
    if (item.bid < buyer.credit) {
        res.push(item.id);
    }
});
return res;

评估后(将其置于mongoose.connection.db.eval("...")电话中),您将获得项目ID的数组。

小心使用它。如果您的allNearItems数组太大或者您经常查询它,您可能会遇到性能问题。 MongoDB团队实际上已经弃用了直接js代码执行,但它仍然可以在当前的稳定版本中使用。