31

似乎在stackoverflow上有很多关于这个主题的问答,但我似乎无法在任何地方找到确切的答案。

我有的:

我有公司和个人模型:

var mongoose = require('mongoose');
var PersonSchema = new mongoose.Schema{
                        name: String, 
                        lastname: String};

// company has a reference to Person
var CompanySchema = new mongoose.Schema{
                        name: String, 
                        founder: {type:Schema.ObjectId, ref:Person}};

我需要的:

查找姓氏为 "Robertson" 的人创建的所有公司

我尝试了什么:

Company.find({'founder.id': 'Robertson'}, function(err, companies){
    console.log(companies); // getting an empty array
});

然后我发现 Person 不是嵌入的而是被引用的,所以我使用 populate 来填充创始人-Person,然后尝试使用带有“Robertson”姓氏的 find

// 1. retrieve all companies
// 2. populate their founders
// 3. find 'Robertson' lastname in populated Companies
Company.find({}).populate('founder')
       .find({'founder.lastname': 'Robertson'})
       .exec(function(err, companies) {
        console.log(companies); // getting an empty array again
    });

我仍然可以用 Person 的 id 作为字符串来查询公司。但这并不是你能理解的我想要的

Company.find({'founder': '525cf76f919dc8010f00000d'}, function(err, companies){
    console.log(companies); // this works
});
4

3 回答 3

48

您不能在单个查询中执行此操作,因为 MongoDB 不支持连接。相反,您必须将其分解为几个步骤:

// Get the _ids of people with the last name of Robertson.
Person.find({lastname: 'Robertson'}, {_id: 1}, function(err, docs) {

    // Map the docs into an array of just the _ids
    var ids = docs.map(function(doc) { return doc._id; });

    // Get the companies whose founders are in that set.
    Company.find({founder: {$in: ids}}, function(err, docs) {
        // docs contains your answer
    });
});
于 2013-10-15T12:56:35.593 回答
11

我已经很晚了:p 但我只是在寻找一个类似的答案,我想我会分享我想出的东西,以防有人出于同样的原因找到这个。

我找不到通过猫鼬查询实现这一目标的方法,但我认为它可以使用MongoDB 聚合管道

要获得您正在寻找的查询,您可以执行以下操作:

const result=await Company.aggregate([
    {$lookup: {
        from: 'persons', 
        localField: 'founder', 
        foreignField: '_id', 
        as: 'founder'}
    },
    {$unwind: {path: '$founder'}},
    {$match: {'founder.lastname': 'Robertson'}}
]);

$lookup就像.populate(),用实际数据替换引用。它返回一个数组,因为它可以用于匹配多个文档。

$unwind从数组中删除项目,在这种情况下,只会将单个元素数组转换为字段。

$match然后做它听起来的样子,只返回与查询匹配的文档。如果需要,您还可以进行比严格相等更复杂的匹配。

一般来说,聚合管道的工作方式是在每个步骤中不断过滤/修改匹配的文档,直到你得到你想要的。

我还没有检查过这方面的性能,但我绝对更喜欢让 Mongo 来做这项工作,而不是过滤掉服务器端不必要的结果。

我想唯一的缺点是结果将只是一个对象数组而不是猫鼬模型,因为管道通常会改变文档的形状。因此,您将无法对返回的数据使用模型的方法。

于 2020-03-16T22:28:39.917 回答
1

万一最近有人遇到这种情况,Mongoose 现在支持加入类似功能的功能称为 Populate。

从猫鼬文档中:

Story.findOne({ 
    title: 'Casino Royale' 
}).populate('author').exec(function (err, story) {
    if (err) return handleError(err);
    console.log('The author is %s', story.author.name);
    // prints "The author is Ian Fleming"
});

http://mongoosejs.com/docs/populate.html

于 2018-02-01T01:58:19.297 回答