【问题标题】:Find documents by array of embedded references in Moongoose (MongoDB)通过 Mongoose (MongoDB) 中的嵌入引用数组查找文档
【发布时间】:2017-06-27 15:57:08
【问题描述】:

假设我有以下集合架构

var terminalSchema = new mongoose.Schema({
    name: 'String', 
    ip: 'String'
});

var wayPointSchema = new mongoose.Schema({
    name: 'String',
    description: 'String',
    long: 'Number',
    lat: 'Number',
    distances: [{
        toTerminal : { type: Schema.Types.ObjectId, ref: 'Terminal' },
        km : 'Number',
        minutes: 'Number'
    }]
});

如何找到所有带有 terminal.ip = '10.0.0.1' 的 WayPoints

我尝试了以下没有运气...

WayPoint.find()
.populate({
    path: 'distances.toTerminal',
    match:  { 'distances.toTerminal.ip': '10.0.0.1'},
})
.exec(function(err, wp) {
    if(err || !wp) {
          throw err;
        } else {
          console.log(wp);
        }
})

返回整个集合

更新 - 进展?

我认为我在以下代码方面取得了一些进展,因为它现在只显示 [object] 用于匹配的子文档,null 用于不匹配的子文档。

WayPoint.find({'distances.toTerminal': {$exists: true}})
.populate({
    path: 'distances.toTerminal',
    select: 'description',
    match:  { ip: '10.0.0.1'}
})
.exec(function(err, wp) {
    if(err || !wp) {
          throw err;
        } else {
          console.log(wp);
        }
})

【问题讨论】:

    标签: javascript node.js mongodb mongoose mongodb-query


    【解决方案1】:

    这里.populate() 的“匹配”部分实际上并不是来自“WayPoint”对象的“完整”可视化路径,而是实际上仅适用于“终端”对象。 “WayPoint”只有参考,所以你这样做:

    WayPoint.find()
        .populate({
            "path": "distances.toTerminal",
            "match": { "ip": "10.0.0.1" }
        })
        .exec(function(err,wp) {
            if (err) throw err;  // or otherwise handle
    
            wp = wp.filter(function(doc) {
                doc.distances = doc.distances.filter(function(distance) {
                    return distance.toTerminal != null;
                });
                return doc.distances.length > 0;
            });
    
            console.dir(wp);
        });
    

    这确实不是通过“终端”IP 值查找“WayPoint”的一种非常有效的方法,因为 mongoose 实际上会获取所有“WayPoint”项目,您必须自己“过滤”才能找到匹配的项目.

    更好的方法是“嵌入”文档,然后您可以发出顶级查询以仅查找匹配的文档:

    WayPoint.find({ "distances.toTerminal.ip": "10.0.0.1" },function(err,wp) {
    

    这是一般的 MongoDB 方式,但如果您不能这样做或者不切实际,那么您最好找到匹配的“终端”对象的 _id 并将其传递给您的“WayPoint”询问。来自“异步”库的一点帮助来清理代码:

    async.waterfall(
        [
            function(callback) {
                Terminal.find({ "ip": "10.0.0.1" },function(err,terms) {
                    if (err) throw err;
                    ids = terms.map(function(term) { return term._id; });
                    callback(err,ids);
                });
            },
    
            function(ids,callback) {
                WayPoint.find(
                   { "distances.toTerminal": { "$in": ids } },
                   function(err,wp) {
                       if (err) throw err;
                       console.dir( wp );
                       callback();
                   }
                );
            }
        ]
    );
    

    【讨论】:

    • @NeilLuhn 感谢您提供全面而及时的回答。我没有嵌入Terminal 的唯一原因是为了跨多个航路点的“可重用性”。您是否建议我保留终端模式以便用户可以轻松找到终端,然后将 terminal 文档的“副本”嵌入到 WayPoint 中?
    • @Habib 那将是一个选项是的。只要您可以在需要时在多个地方进行“更新”。但一般的一点是,如果您想通过“ip”或有关该数据的其他信息进行查询,那么您希望在您的“WayPoint”对象中可以访问它,如第二个查询表单所示。这是最有效的方法。
    猜你喜欢
    • 1970-01-01
    • 2011-08-11
    • 2013-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 2021-06-06
    • 1970-01-01
    相关资源
    最近更新 更多