使用Mongoose进行条件字段选择

时间:2014-01-07 02:35:56

标签: mongodb mongoose

假设我有一组用户名和电子邮件地址的用户。

{ name: 'John Doe', email: 'john@doe.com', level: 5 }
{ name: 'Fred Foo', email: 'fred@foo.com', level: 2 }
{ name: 'Jo Green', email: 'jo@green.com', level: 5 }
{ name: 'Paul Bar', email: 'paul@bar.com', level: 3 }

我想查询此集合,选择所有用户的名称和级别。在Mongoose,我可以这样做:

User
  .find()
  .select('name level')
  .exec(callback)

这会给我以下内容:

{ name: 'John Doe', level: 5 }
{ name: 'Fred Foo', level: 2 }
{ name: 'Jo Green', level: 5 }
{ name: 'Paul Bar', level: 3 }

但如果用户的级别高于4,我还想获得他们的电子邮件地址。这会给我以下内容:

{ name: 'John Doe', email: 'john@doe.com', level: 5 }
{ name: 'Fred Foo', level: 2 }
{ name: 'Jo Green', email: 'paul@bar.com', level: 5 }
{ name: 'Paul Bar', level: 3 }

Mongo [ose]的最佳效果是什么?

2 个答案:

答案 0 :(得分:4)

不,MongoDb目前在一个查询中没有根据条件选择性地返回不同的字段集。 MongoDb中的查询和关联的投影适用于所有文档。

map reduce不能这样做(因为map reduce需要为每个文档返回相同的值)并且不合适。聚合不是许多查询的通用替代方法,并且有条件地返回字段会很复杂。

您有几个选择:

  1. 执行多个查询并合并结果。这将非常简单,因为每个结果都是一个数组,所以你可以合并数组。
  2. 返回所有字段的超集并过滤您的应用代码。
  3. 我会测试选项的性能。两者都不复杂。

答案 1 :(得分:1)

正如WiredPrairie所说,这在一个查询中是不可能的。使用聚合和一些应用程序代码可以轻松完成。要仅返回级别高于4的电子邮件,以下聚合将起作用:

User.aggregate().match({})
  .project({
    'name': 1,
    'email': {
      $cond: {
        if: {
          '$gt': ['$level', 4]
        },
        then: '$email',
        else: null
      }
    },
    'level': 1
  })
  .exec(callback);

使用lodash或underscore等实用程序库可以直接删除结果集中的任何空电子邮件。在回调函数中,以下lodash函数将删除任何空电子邮件:

var callback = function(err, users) {
  return _.map(users, function(user) {
    return _.omitBy(user, _.isNull);
  });
};