【问题标题】:Is it possible to get single result in aggregate?是否有可能获得单一结果?
【发布时间】:2014-10-15 05:47:00
【问题描述】:

是否可以像db.collection.findOne 一样在db.collection.aggregate 上获取单个文档?

【问题讨论】:

  • 不清楚您在这里要求什么。具体来说,您应该解释您想要做什么。顺便说一句,到目前为止给出的答案在大多数情况下都是错误的。
  • 您尝试过聚合([....]).toArray()[0].total 吗?

标签: mongodb


【解决方案1】:

是的,这是可能的。只需添加一个$group 阶段,_id 等于null。这将计算所有输入文档作为一个整体的累积值。例如

{ $group: { _id: null, total: { $sum: "$price" }}}

或者如果您只想从聚合结果中获取一个文档,您可以使用$limit

{ $limit: 1 }

更新:这两种解决方案都返回 cursor ,它只有一个文档。但不要将findOne 视为特别的东西。它还检索光标并仅获取第一个文档(如果有)。这是findOne的mongo shell实现:

function ( query , fields, options ){
    var cursor = this.find(query, fields, -1 /* limit */, 0 /* skip*/,
        0 /* batchSize */, options);

    if ( ! cursor.hasNext() )
        return null;
    var ret = cursor.next();
    if ( cursor.hasNext() ) throw "findOne has more than 1 result!";
    if ( ret.$err )
        throw "error " + tojson( ret );
    return ret;
}

如您所见,它在内部使用find。因此,如果您想获取单个文档而不是单个文档的光标,您可以编写自己的函数,该函数与 aggregate 相同。例如

> DBCollection.prototype.aggregateOne = function(pipeline) {
     var cur = this.aggregate(pipeline);
     if (!cur.hasNext())
         return null; 
     return cur.next(); 
 }

用法:

> db.collection.aggregateOne(...)

【讨论】:

  • 不幸的是我仍然得到一个包含一个元素的数组
  • Bullseye (y),解释得很好。
【解决方案2】:

可以将$match 阶段添加到聚合管道。但即使它只匹配一个文档,结果仍然是一个列表(在这种情况下长度为 1)。所以答案是“NO,不可能”。

【讨论】:

    【解决方案3】:

    是的,这是可能的。你需要使用mongodb$match操作

    例如:这对我有用。

    { $lookup: { from: 'user', localField: 'userId', foreignField: 'id', as: 'publisherDetails' } },
    { $match: { id } }
    

    mondodb doc's 示例:

    db.articles.aggregate(
    [ { $match : { id : "132ada123aweae1321awew12" } },
      { $lookup: { from: 'user', localField: 'userId', foreignField: 'id', as: 'publisherDetails' } } ]
    );
    

    【讨论】:

      【解决方案4】:

      如果“通过单个结果” 你的意思是findOne 风格的返回类型,应该不可能这样做。虽然不是说不可能,但应该也应该这样对待。聚合操作是 documented 仅返回 aggregate cursors,因此聚合操作的唯一可靠结论应该是 aggregate cursorerror。当您收到聚合光标时,您可以使用其公开的方法来访问您的单个文档。期待其他任何事情都类似于追求混乱。

      Ps:到这个帖子的时间很晚。希望对以后可能会在这里结束的其他人有所帮助。

      【讨论】:

        【解决方案5】:

        在 Python 中,您可以将结果转换为列表并获取第一个元素:

        result = list(mongo.db.collection.aggregate([{"$sample": {"size": 1}}]))[0]
        

        【讨论】:

          【解决方案6】:

          只是为了用另一个简单的解决方案改进答案,并避免编写大量重复的代码,这是我基于@Sergey Berezovskiy 答案的解决方案。

          import { Collection } from 'mongodb';
          
          Collection.prototype.aggregateOne = async function(pipeline, options) {
             const items = await this.aggregate(pipeline, options).toArray();
             return items.length > 0 ? items[0] : null; 
          }
          

          就像普通的聚合函数一样,你可以像这样使用:

          return db.articles.aggregateOne(
             [ { $match : { id : "132ada123aweae1321awew12" } },
             { $lookup: { from: 'user', localField: 'userId', foreignField: 'id', as: 'publisherDetails' } } ]
          );
          

          如果存在或为空,这将返回第一个文档。

          希望这会促进某人的生活。

          【讨论】:

          • 为什么不这样做呢? const item = await this.aggregate(pipeline, options).toArray()[0] || null;
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-06
          • 1970-01-01
          • 2020-08-29
          • 1970-01-01
          • 2011-05-02
          • 2018-04-13
          • 2020-01-13
          相关资源
          最近更新 更多