通过Moongoose(MongoDB)中的嵌入式引用数组查找文档

时间:2022-05-10 18:18:39

Assuming I have the following collection schema

假设我有以下集合架构

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'
    }]
});

How can I find all WayPoints with terminal.ip = '10.0.0.1'

如何通过terminal.ip = '10 .0.0.1找到所有WayPoints

I have tried the following with no luck...

我试过以下没有运气......

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

The entire collection is returned

返回整个集合

Update - Progress?

更新 - 进展?

I think I've made some progress with the following code, as it now only shows [object] for matching sub-documents and null for sub-documents that don't match.

我想我已经在下面的代码中取得了一些进展,因为它现在只显示匹配子文档的[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);
        }
})

1 个解决方案

#1


3  

The "match" part of .populate() here is not actually the "full" visualized path from the "WayPoint" object but actually only applies to the "Terminal" object. The "WayPoint" only has the reference so you do this:

这里.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);
    });

That really isn't a very efficient way to find a "WayPoint" by the "Terminal" ip value as mongoose actually fetches all "WayPoint" items and you have to "filter" yourself in order to find the ones that matched.

这真的不是通过“终端”ip值找到“WayPoint”的非常有效的方法,因为mongoose实际上获取所有“WayPoint”项目,并且您必须“过滤”自己以找到匹配的项目。

The better way would be to "embed" the document, then you can issue the top level query to find only documents that match:

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

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

That is the general MongoDB way, but if you cannot do that or it is otherwise impractical, then you would be better of finding the _id of the matching "Terminal" object or objects and passing that to your "WayPoint" query. A little help from the "async" library to clean up the code:

这是一般的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();
               }
            );
        }
    ]
);

#1


3  

The "match" part of .populate() here is not actually the "full" visualized path from the "WayPoint" object but actually only applies to the "Terminal" object. The "WayPoint" only has the reference so you do this:

这里.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);
    });

That really isn't a very efficient way to find a "WayPoint" by the "Terminal" ip value as mongoose actually fetches all "WayPoint" items and you have to "filter" yourself in order to find the ones that matched.

这真的不是通过“终端”ip值找到“WayPoint”的非常有效的方法,因为mongoose实际上获取所有“WayPoint”项目,并且您必须“过滤”自己以找到匹配的项目。

The better way would be to "embed" the document, then you can issue the top level query to find only documents that match:

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

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

That is the general MongoDB way, but if you cannot do that or it is otherwise impractical, then you would be better of finding the _id of the matching "Terminal" object or objects and passing that to your "WayPoint" query. A little help from the "async" library to clean up the code:

这是一般的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();
               }
            );
        }
    ]
);