3

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

shop: {
  _id: '...'
  title: 'my shop'
  users: [
    {
      _id: '...',
      name: 'user1',
      username: '...'
    },
    {
      _id: '...',
      name: 'user2',
      username: '...'
    }
  ]
}

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

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

输出:

{ _id: ...,
  users: 
   [{
     name: 'user1',
     username: '...',
     _id: ...
    }]
}

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

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

但是有没有更好的方法在查询中完成这一切?

4

2 回答 2

7

这个问题已经快两年了,但我注意到人们仍在寻找解决这个问题的方法。fernandopasik 的回答对我帮助很大,但缺少有关如何使用建议的聚合操作的代码示例。这就是为什么我发布更详细的答案。我使用的文件是:

{
  _id: '...'
  title: 'my shop'
  users: [
    {
      _id: 'user1Id',
      name: 'user1',
      username: '...'
    },
    {
      _id: 'user2Id',
      name: 'user2',
      username: '...'
    }
  ]
}

我想出的解决方案(在阅读了关于聚合的 mongodb 文档之后)是:

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

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

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

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

{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user1Id',
    name: 'user1',
    username: '...'
  }
}
{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user2Id',
    name: 'user2',
    username: '...'
  }
}

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

{
  _id: '...',
  title: 'my shop',
  users: {
    _id: 'user2Id',
    name: 'user2',
    username: '...'
  }
}

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

{name: 'user2'}

聚合管道一开始并不容易掌握。我建议通读 mongodb 聚合文档并一次尝试一个聚合操作。有时很难在整个聚合管道中发现错误。大多数情况下,当管道中某处出现错误时,您根本无法从管道中获得任何结果文档。

于 2015-08-10T06:35:22.850 回答
2

您应该尝试使用 mongoose 的 mongodb 聚合框架:

http://mongoosejs.com/docs/api.html#aggregate-js

我建议你先申请unwind用户,然后匹配用户 id,然后投影用户名。

于 2013-11-04T05:07:59.167 回答