【问题标题】:Mongoose select record with subdocuments count less than XMongoose 选择子文档数小于 X 的记录
【发布时间】:2019-12-23 18:52:24
【问题描述】:

我有 nodejs/mongodb 和 mongoose 设置。一切都是最后一个版本。

我在 NOSQL 中有点“全新”,并尝试使用 NOSQL 和 mongoose ORM 重写此类 SQL 查询:

select * from documents where count(select * from subdocuments where subdocuments.documentId = documents.id) = 5 order by documents.id desc limit 1

在我的例子中(嵌套集合),主要的集合结构是:

   documents: [{
         _id: ObjectId
         subdocuments: [{
              _id: ObjectId
         }]
   }]

所以我只需要使用documents.findOne mongoose 函数获取最后一个子文档数 = 5 的对象。

是否可以使用 mongodb/mongoose 进行所有这些聚合?我找不到与我的案件相关的任何内容。

谢谢!

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    您可以使用$size 运算符来查找具有指定长度的数组字段的文档:

    await documents.findOne({ subdocuments: { $size: 5 } });
    

    在您的情况下,您希望以降序获取带有_id 的最后一个文档,以便您可以将排序选项添加到findOne()

    await documents.findOne({ subdocuments: { $size: 5 } }, {}, { sort: { '_id' : -1 } });
    

    或者:

    await documents.findOne({ subdocuments: { $size: 5 } }).sort({_id: -1});
    

    要查找子文档长度小于 5 的文档,可以使用 $where 运算符:

    await documents.findOne({$where: 'this.subdocuments.length<5'}, {}, { sort: { '_id' : -1 } });
    

    【讨论】:

    • 看起来棒极了!谢谢你。我不敢相信这很容易
    • 还有一件事——$size
    • 为此,您可能需要使用$where,例如{$where: 'this.subdocuments.length&lt;5'}。如果有帮助,请告诉我。
    【解决方案2】:

    有一个名为$expr 的运算符允许您在查询语言中使用聚合表达式。这非常方便 在这里,您需要在查找查询中使用聚合运算符。

    将您的查询分解成块以便理解,让我们进行检查

    subdocuments.documentId = documents.id
    

    在 mongo 中,这意味着迭代 subdocuments 数组搜索满足上述条件的子文档,可以使用以下方式表示 $filter:

    {
        '$filter': {
            'input': '$subdocuments',
            'cond': { '$eq': ['$$this._id', '$_id'] }
        }
    }
    

    计数位通常用$size 运算符表示,因此从上面获取结果,此查询

    count(select * from subdocuments where subdocuments.documentId = documents.id)
    

    被翻译成表达式

    {
        '$size': {
            '$filter': {
                'input': '$subdocuments',
                'cond': { '$eq': ['$$this._id', '$_id'] }
            }
        }
    }
    

    使用比较运算符$gt满足条件

    where count(select * from subdocuments where subdocuments.documentId = documents.id) > 5
    

    作为

    {
        '$gt': [
            { '$size': {
                '$filter': {
                    'input': '$subdocuments',
                    'cond': { '$eq': ['$$this._id', '$_id'] }
                }
            } },
            5
        ]
    }
    

    对于相等性,用$eq 显示是微不足道的

    {
        '$eq': [
            { '$size': {
                '$filter': {
                    'input': '$subdocuments',
                    'cond': { '$eq': ['$$this._id', '$_id'] }
                }
            } },
            5
        ]
    }
    

    然后可以将上述内容与find() 查询一起使用 $expr as

    db.collection.find({
        '$expr': {
            '$eq': [
                { '$size': {
                    '$filter': {
                        'input': '$subdocuments',
                        'cond': { '$eq': ['$$this._id', '$_id'] }
                    }
                } },
                5
            ]
        }
    })
    

    分别使用sort()limit()游标方法进行排序和限制

    db.collection.find({
        '$expr': {
            '$eq': [
                { '$size': {
                    '$filter': {
                        'input': '$subdocuments',
                        'cond': { '$eq': ['$$this._id', '$_id'] }
                    }
                } },
                5
            ]
        }
    }).sort({ '_id': -1 }).limit(1)
    

    这个查询也有一个聚合变体。使用aggregation framework,管道中使用的表达式是相似的。

    查找部分在$match 管道步骤中完成:

    db.collection.aggregate([
        { '$match': {
            '$expr': {
                '$eq': [
                    { '$size': {
                        '$filter': {
                            'input': '$subdocuments',
                            'cond': { '$eq': ['$$this._id', '$_id'] }
                        }
                    } },
                    5
                ]
            }
        } }
    ])
    

    排序和限制分别在$sort$limit 管道阶段内进行管道传输

    db.collection.aggregate([
        { '$match': {
            '$expr': {
                '$eq': [
                    { '$size': {
                        '$filter': {
                            'input': '$subdocuments',
                            'cond': { '$eq': ['$$this._id', '$_id'] }
                        }
                    } },
                    5
                ]
            }
        } },
        { '$sort': { '_id': 1 } },
        { '$limit': 1 }
    ])
    

    【讨论】:

      猜你喜欢
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      • 1970-01-01
      • 2018-02-13
      • 2021-10-23
      • 1970-01-01
      • 2011-06-14
      相关资源
      最近更新 更多