使用Mongoose的.populate()方法返回特定字段

130
我在运行查询后从MongoDB得到了一个JSON值。问题是我不想返回与我的返回相关联的所有JSON,我尝试搜索文档,但没有找到适当的方法来做到这一点。我在想是否可能实现此目标,如果可能的话,正确的操作方式是什么。例如:在数据库中。
{
    user: "RMS",
    OS: "GNU/HURD",
    bearded: "yes",
    philosophy: {
        software: "FOSS",
        cryptology: "Necessary"
    },
    email: {
        responds: "Yes",
        address: "rms@gnu.org"
    },
    facebook: {}
}

{
    user: "zuckerburg",
    os: "OSX",
    bearded: "no",
    philosophy: {
        software: "OSS",
        cryptology: "Optional"
    },
    email: {},
    facebook: {
        responds: "Sometimes",
        address: "https://www.facebook.com/zuck?fref=ts"
    }
} 
如果用户存在某个字段,则返回该字段的正确方式是什么,但如果不存在该字段,则返回另一个字段。 对于上面的示例,我想返回RMS的“[email] [address]”字段,以及Zuckerburg的“[facebook] [address]”字段。 这是我尝试查找字段是否为空,但似乎没有起作用。
 .populate('user' , `email.address`)
  .exec(function (err, subscription){ 
    var key;
    var f;
    for(key in subscription){
      if(subscription[key].facebook != null  ){
          console.log("user has fb");
      }
    }
  }
14个回答

122

我不完全清楚您所说的“返回字段”的含义,但是您可以使用lean()查询,以便您可以自由地修改输出,然后填充两个字段并对结果进行后处理,只保留您想要的字段:

.lean().populate('user', 'email.address facebook.address')
  .exec(function (err, subscription){ 
    if (subscription.user.email.address) {
        delete subscription.user.facebook;
    } else {
        delete subscription.user.email;
    }
  });

1
这对我不起作用,有人知道这是否随着Mongoose更新而改变了吗? - Ninja Coding
1
这对我也不起作用,我尝试过.populate('model', 'field').populate('model', { field: 1}).populate('model', [field]),以及在模型上使用和不使用lean()selectPopulatedPaths: false,但我总是在响应中得到完整的填充对象。文档说你的答案应该是正确的,但我无法使其工作。有人遇到同样的问题吗? - mel-mouk

81

如果您只想返回填充文档的几个特定字段,可以通过将字段名称语法作为第二个参数传递给populate方法来实现此目的。

Model
.findOne({ _id: 'bogus' })
.populate('the_field_to_populate', 'name') // only return the Persons name
...

请查看Mongoose populate字段选择


13
运行良好。您还可以返回更多字段,但必须传递更多字段。 --> populate('要填充的字段','名字 姓氏') - saeta
如果您有多个模型需要填充,并且想要为它们提供字段,例如populate('users posts','name'),那该怎么办?您会同时获取两个模型的名称吗? - MoDrags
类似这样的代码: Model.findOne({_id: 'foo'}).populate({ path: 'parent-model', populate: { path: 'someProperty', populate: { path: 'somePropertyBelow' } } }) - dontmentionthebackup

57

尝试做到这一点:

applicantListToExport: function (query, callback) {
  this
   .find(query).select({'advtId': 0})
   .populate({
      path: 'influId',
      model: 'influencer',
      select: { '_id': 1,'user':1},
      populate: {
        path: 'userid',
        model: 'User'
      }
   })
 .populate('campaignId',{'campaignTitle':1})
 .exec(callback);
}

4
这里需要解释一下正在发生的事情: 这是为了在嵌套填充和简单填充中选择字段。 - Andre Simon
你救了我的一天 :) - Peshraw H. Ahmed

29

试着做这个:

User.find(options, '_id user email facebook').populate('facebook', '_id pos').exec(function (err, users) {

28

现在你可以做的是:

  .populate('friends', { username: 1, age: 1})

14
在下面的查询中,我检索匹配条件show=true的文章,检索到的数据包括标题和创建时间,同时也检索到文章所属类别的标题和ID,但只有标题被检索出来。
let articles = await articleModel
        .find({ show: true }, { title: 1, createdAt: 1 })
        .populate("category", { title: 1, _id: 1 });

简单而优雅 - Phantom007

8

如果要进行单层填充,您可以使用 -> populate('user', 'name email age')

如果要进行嵌套填充

populate({
    path:'posts',
    populate({
         path:'user'
         select:'name email age'
    })
})

4
我卡在了这个问题上。我想用populator来填充与博客文章有关的用户字段。 只使用populate返回的是包括密码在内的所有内容。通过将字段指定为数组,它就可以正常工作。

//出于简洁考虑省略了代码

await Blog.findById(ID).populate("author", ["firstName", "lastName", 
"profilePicture", "_id"])

//

这是响应的结果

响应


4

请试一试:

Post.find({_id: {$nin: [info._id]}, tags: {$in: info.tags}}).sort({_id:-1})
.populate('uid','nm')
.populate('tags','nm')
.limit(20).exec();

2

补充一下前面的答案,如果你想包括所有内容但又想排除某些属性,可以按照以下方式操作:

.populate('users', {password: 0, preferences: 0})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接