【问题标题】:Mongoose - How to query field in the last object of an array of objectsMongoose - 如何查询对象数组的最后一个对象中的字段
【发布时间】:2022-02-20 08:51:40
【问题描述】:

我的 MongoDB 文档结构如下:

{
    "_id": "5d8b987f9f8b9f9c8c8b9f9",
    "targetsList": [
        {
            "target": "user",
            "statusList": [
                {
                    "date": "2018-01-01",
                    "type": "OK"
                },
                {
                    "date": "2018-01-02",
                    "type": "FAILD"
                }
            ]
        }
    ]
}

我想计算所有文档,在它们的 "targetList" 数组中,有一个带有 "target"=="user" 的对象 - 还有那个对象包含在其 "statusList" 数组的 last 元素上,这是一个具有 "type" != "FAILD" 的对象。

关于如何实现这种查询的任何想法?

Mongo 游乐场: https://mongoplayground.net/p/3bCoHRnh-KQ 在此示例中,我希望计数为 1,因为只有第二个对象满足条件。

【问题讨论】:

  • 你可以分享一个样本数据集,也许使用 mongoplayground.net。你想要的结果也不是很清楚
  • @cmgchess 感谢您的反馈,我添加了一个游乐场。
  • 所以如果数组至少有 1 个 FAILD 它应该算吗?还是必须是数组中的最后一个元素
  • @cmgchess 仅当内部数组(“statusList”)中的 last 元素为not FAILD。

标签: node.js mongodb mongoose mongodb-query


【解决方案1】:

聚合管道
第一步 - 过滤出"targetsList.target": "user"
第二步 - $unwind on targetsList 将其排除在外数组
第三步 - 使用 $arrayElemAt 获取 targetsList.statusList 数组的最后一个元素
第四步 - 获取最后一个元素不是的结果失败
第五步 - 计数

demo - 您可以尝试移除部分管道以查看中间结果是什么

db.collection.aggregate([
  {
    $match: {
      "targetsList.target": "user"
    }
  },
  {
    $unwind: "$targetsList"
  },
  {
    $project: {
      "targetsList.statusList": {
        $arrayElemAt: [
          "$targetsList.statusList",
          -1
        ]
      },
      
    }
  },
  {
    $match: {
      "targetsList.statusList.type": {
        $ne: "FAILD"
      }
    }
  },
  {
    $count: "withoutFailedInLastElemCount"
  }
])

【讨论】:

  • 谢谢。但我刚刚发现这个解决方案不准确。 mongoplayground.net/p/7tJIEZ7693M 在这里你可以看到,如果相同的“targetList”也包含目标“user”,它也会计算带有“target == admin”的元素。 (参见第二个元素中的示例)。我们只需要计算具有“target == user”的元素。
  • @dev3dev 我在第一个匹配项中添加了大小 1。你在寻找类似mongoplayground.net/p/LkuDvh_5cnK
  • 现在查询只查找“targetLis”大小为 1。相反,我需要的是它还将查看“targetList”与多个目标(就像那里的第二个文档),但它只会计算目标“用户”并忽略其他目标。例如这里计数结果应该是1:mongoplayground.net/p/LkuDvh_5cnK
  • mongoplayground.net/p/eRbI0gArOnM 用这个检查一下。我把展开放在前面,所以它首先分成单个对象,然后匹配用户
  • 但是现在如果 targetlist 有两个没有失败的用户,它将计为 2。这是你想要的还是?
【解决方案2】:

除非元素是最后一个索引很重要,否则这应该适用于您的情况。

db.collection.find({
  "targetsList.statusList.type": {
    $in: [
      "FAILD"
    ]
  }
})

这将检索type 值为FAILD 的文档。要反转这一点,您可以将$in 换成$nin

更新游乐场here

【讨论】:

  • 谢谢,但我不想知道它是否在 in,我想知道它是否在数组的 last 元素中。
【解决方案3】:

这是另一种方法来处理领先的怪物“$match”。

db.collection.aggregate([
  {
    "$match": {
      "targetsList.target": "user",
      "$expr": {
        "$reduce": {
          "input": "$targetsList",
          "initialValue": false,
          "in": {
            "$or": [
              "$$value",
              {
                "$ne": [
                  {
                    "$last": "$$this.statusList.type"
                  },
                  "FAILD"
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    "$count": "noFailedLastCount"
  }
])

试试mongoplayground.net

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-04
    • 2021-06-23
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 2021-11-06
    相关资源
    最近更新 更多