如何在mongoose中通过id查找子文档并排除某些字段

bek*_*ite 3 mongoose mongodb

我有一个存储在mongodb中的文件:

shop: {
  _id: '...'
  title: 'my shop'
  users: [
    {
      _id: '...',
      name: 'user1',
      username: '...'
    },
    {
      _id: '...',
      name: 'user2',
      username: '...'
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我使用此查询通过其id获取子文档用户:

Shop.findOne({'users._id': userId}, {'users.$': 1}, function (err, user) {
  console.log(user);
});
Run Code Online (Sandbox Code Playgroud)

输出:

{ _id: ...,
  users: 
   [{
     name: 'user1',
     username: '...',
     _id: ...
    }]
}
Run Code Online (Sandbox Code Playgroud)

如何过滤结果以仅返回用户名.我现在这样做的方式:

Shop.findOne({'users._id': userId}, {'users.$': 1}, function (err, shop) {
  shop = shop.toObject()
  user = shop.users[0]
  filtered = {
    name: user.name
  }
  callback(filtered);
});
Run Code Online (Sandbox Code Playgroud)

但是有更好的方法在查询中完成所有操作吗?

bek*_*ite 7

这个问题差不多有两年了,但我注意到人们仍然在寻找解决这个问题的方法.fernandopasik的回答对我很有帮助,但缺少关于如何使用建议的聚合操作的代码示例.这就是我发布更详细答案的原因.我使用的文件是:

{
  _id: '...'
  title: 'my shop'
  users: [
    {
      _id: 'user1Id',
      name: 'user1',
      username: '...'
    },
    {
      _id: 'user2Id',
      name: 'user2',
      username: '...'
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我提出的解决方案(在阅读有关聚合的mongodb文档后​​)是:

Shop.aggregate([
  {$unwind: '$users'},
  {$match: {'users._id': 2}},
  {$project: {_id: 0, 'name': '$users.name'}}
]);
Run Code Online (Sandbox Code Playgroud)

要了解聚合如何工作,最好一次尝试一个操作并阅读此操作的mongodb文档.

  1. Shop.aggregate([{$unwind: '$users'}])

$ unwind解构用户数组(不要忘记在数组名称中包含$),所以最终得到:

{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user1Id',
    name: 'user1',
    username: '...'
  }
}
{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user2Id',
    name: 'user2',
    username: '...'
  }
}
Run Code Online (Sandbox Code Playgroud)

2. {$match: {'users._id': 'user2Id'}}在聚合管道上使用(本例中的两个文档)将返回users._id为'user2Id'的整个文档:

{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user2Id',
    name: 'user2',
    username: '...'
  }
}
Run Code Online (Sandbox Code Playgroud)

3.仅返回名称:'user2'可以使用{$project: {_id: 0, 'name': '$users.name'}}:

{name: 'user2'}
Run Code Online (Sandbox Code Playgroud)

聚合管道起初并不容易掌握.我建议阅读mongodb聚合文档并一次尝试一个聚合操作.有时很难发现整个聚合管道中的错误.大多数情况下,当管道中某处出现错误时,您只是从管道中获取结果文档.