返回具有最大子文档的文档

2023-12-19

我试图根据日期值返回一个包含最大子文档的文档。到目前为止,我能够创建正确的对象,但是查询返回所有子文档而不是具有最大日期的子文档。例如,我的数据存储为:

{ value: 1,
  _id: 5cb9ea0c75c61525e0176f96,
  name: 'Test',
  category: 'Development',
  subcategory: 'Programming Languages',
  status: 'Supported',
  description: 'Test',
  change:
   [ { version: 1,
       who: 'ATL User',
       when: 2019-04-19T15:30:39.912Z,
       what: 'Item Creation' },
     { version: 2,
       who: 'ATL Other User',
       when: 2019-04-19T15:30:39.912Z,
       what: 'Name Change' } ],
}

在我的查询中,我选择具有相同的所有项目subcategory,以及拥有他们的name存在。然后,我将所需的所有值投影到对象中,展开数组并对其进行排序,然后返回查询结果。就结构而言,这让我得到了此处建模的正确输出:

{
  _id: 5cb9ea0c75c61525e0176f96,
  name: 'Test',
  category: 'Development',
  subcategory: 'Programming Languages',
  status: 'Supported',
  description: 'Test',
  change: {
      "who": "ATL User",
      "when": ISODate("2019-04-19T17:11:36Z")
  }
}

这里的问题是,如果一个文档有多个子文档或版本,那么查询也会返回这些子文档而不是忽略它们,只留下最大日期(如果项目Test有三个版本,然后是三个Test文件被退回)。

为了通过此查询否定其他文档,我应该查看什么?

db.items.aggregate([
    {$match: {subcategory: "Programming Languages", name: {$exists: true}}}, 
    {$project: {"name": 1, 
                "category": 1,
                "subcategory": 1,
                "status": 1,
                "description": 1,
                "change.who": 1,
                "change.when": {$max: "$change.when"}}},
    {$unwind: "$change"},
    {$sort: {"change.when": -1}}
]);

首先,让我们以人们可以使用它并产生所需结果的方式显示您的数据:

{ value: 1,
  _id: ObjectId('5cb9ea0c75c61525e0176f96'),
  name: 'Test',
  category: 'Development',
  subcategory: 'Programming Languages',
  status: 'Supported',
  description: 'Test',
  change:
   [ { version: 1,
       who: 'ATL User',
       when: new Date('2019-04-19T15:30:39.912Z'),
       what: 'Item Creation' },
     { version: 2,
       who: 'ATL Other User',
       when: new Date('2019-04-19T15:31:39.912Z'),
       what: 'Name Change' } ],
}

请注意,"when"日期实际上是不同的,所以会有一个$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/值并且它们不只是相同。现在我们可以回顾一下案例

案例 1 - 获取“单数”$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value

这里的基本情况是使用$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/ and $indexOfArray https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/运算符返回匹配的$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value:

db.items.aggregate([
  { "$match": {
    "subcategory": "Programming Languages", "name": { "$exists": true }
  }}, 
  { "$addFields": {
    "change": {
      "$arrayElemAt": [
        "$change",
        { "$indexOfArray": [
          "$change.when",
          { "$max": "$change.when" }
        ]}
      ]
    }
  }}
])

Returns:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : {
                "version" : 2,
                "who" : "ATL Other User",
                "when" : ISODate("2019-04-19T15:31:39.912Z"),
                "what" : "Name Change"
        }
}

基本上是"$max": "$change.when"返回该值数组中的“最大值”。然后,您可以通过以下方式找到该值数组的匹配“索引”$indexOfArray https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/它返回first找到匹配的索引。该“索引”位置(实际上只是一个数组"when"以相同顺序转置的值)然后与$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/从中提取“整个对象”"change"指定索引位置处的数组。

情况 2 - 返回“倍数”$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ entries

几乎同样的事情$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/,除了这次我们$filter https://docs.mongodb.com/manual/reference/operator/aggregation/filter/返回倍数“可能的”匹配的值$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value:

db.items.aggregate([
  { "$match": {
    "subcategory": "Programming Languages", "name": { "$exists": true }
  }}, 
  { "$addFields": {
    "change": {
      "$filter": {
        "input": "$change",
        "cond": {
          "$eq": [ "$$this.when", { "$max": "$change.when" } ]
        }
      }       
    }
  }}
])

Returns:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 2,
                        "who" : "ATL Other User",
                        "when" : ISODate("2019-04-19T15:31:39.912Z"),
                        "what" : "Name Change"
                }
        ]
}

So the $max https://docs.mongodb.com/manual/reference/operator/aggregation/max/当然是相同的,但是这次该运算符返回的奇异值用于$eq https://docs.mongodb.com/manual/reference/operator/aggregation/eq/内比较$filter https://docs.mongodb.com/manual/reference/operator/aggregation/filter/。这会检查每个数组元素并查看current "when"价值 ("$$this.when")。在哪里"equal"然后返回该元素。

与第一种方法基本相同,但不同之处在于$filter allows “多种的”要返回的元素。所以一切same $max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value.

情况 3 - 对数组内容进行预排序。

现在您可能会注意到,在我包含的示例数据中(改编自您自己的数据,但具有实际的“最大”日期),“最大”值实际上是last数组中的值。这可能会自然发生,因为$push https://docs.mongodb.com/manual/reference/operator/update/push/( 默认情况下 )“追加”到现有数组内容的末尾。所以"newer"条目往往位于end数组的。

这当然是default行为,但你有充分的理由"may"想要改变这一点。简而言之best的方式来获得“最近”数组条目实际上是返回第一个元素从数组中。

您实际上需要做的就是确保“最近”实际上添加了first而不是last。有两种方法:

  1. Use $position https://docs.mongodb.com/manual/reference/operator/update/position/“预先挂起”数组项:这是一个简单的修改器$push https://docs.mongodb.com/manual/reference/operator/update/push/使用0 position为了始终添加到front:

    db.items.updateOne(
      { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
      { "$push": {
          "change": {
            "$each": [{
              "version": 3,
              "who": "ATL User",
              "when": new Date(),
              "what": "Another change"
            }],
            "$position": 0
          }
       }}
    )
    

    这会将文档更改为:

    {
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 3,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-20T02:40:30.024Z"),
                        "what" : "Another change"
                },
                {
                        "version" : 1,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-19T15:30:39.912Z"),
                        "what" : "Item Creation"
                },
                {
                        "version" : 2,
                        "who" : "ATL Other User",
                        "when" : ISODate("2019-04-19T15:31:39.912Z"),
                        "what" : "Name Change"
                }
        ]
    }
    

请注意,这需要您事先实际“反转”所有数组元素,以便“最新”元素已经位于前面,从而保持顺序。值得庆幸的是,第二种方法在某种程度上涵盖了这一点......

  1. Use $sort https://docs.mongodb.com/manual/reference/operator/update/sort/按顺序修改每个文件$push https://docs.mongodb.com/manual/reference/operator/update/push/:这是另一个修改器,它实际上对每个新项目添加进行原子“重新排序”。正常使用方法与任何新项目基本相同$each https://docs.mongodb.com/manual/reference/operator/update/each/如上所述,甚至只是一个“空”数组以应用$sort https://docs.mongodb.com/manual/reference/operator/update/sort/仅适用于现有数据:

    db.items.updateOne(
      { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
      { "$push": {
          "change": {
            "$each": [],
            "$sort": { "when": -1 } 
          }
       }}
    )
    

    结果是:

    {
            "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
            "value" : 1,
            "name" : "Test",
            "category" : "Development",
            "subcategory" : "Programming Languages",
            "status" : "Supported",
            "description" : "Test",
            "change" : [
                    {
                            "version" : 3,
                            "who" : "ATL User",
                            "when" : ISODate("2019-04-20T02:40:30.024Z"),
                            "what" : "Another change"
                    },
                    {
                            "version" : 2,
                            "who" : "ATL Other User",
                            "when" : ISODate("2019-04-19T15:31:39.912Z"),
                            "what" : "Name Change"
                    },
                    {
                            "version" : 1,
                            "who" : "ATL User",
                            "when" : ISODate("2019-04-19T15:30:39.912Z"),
                            "what" : "Item Creation"
                    }
            ]
    }
    

    可能需要一分钟才能理解为什么你会$push https://docs.mongodb.com/manual/reference/operator/update/push/为了$sort https://docs.mongodb.com/manual/reference/operator/update/sort/像这样的数组,但一般意图是当可能对数组进行修改时,“改变”属性,例如Date值被排序,您将使用这样的语句来反映这些更改。或者实际上只是添加新项目$sort https://docs.mongodb.com/manual/reference/operator/update/sort/并让它解决。

So why "store"数组是这样排序的?正如前面提到的,你想要first项目作为“最近”,然后返回的查询就变成了:

db.items.find(
  {
    "subcategory": "Programming Languages",
    "name": { "$exists": true }
  },
  { "change": { "$slice": 1 } }
)

Returns:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 3,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-20T02:40:30.024Z"),
                        "what" : "Another change"
                }
        ]
}

So the $slice https://docs.mongodb.com/manual/reference/operator/projection/slice/然后可以仅用于通过已知索引提取数组项。从技术上讲你可以使用-1在那里为了返回last无论如何,数组的项目,但是首先重新排序最新的项目允许执行其他操作,例如确认最后一次修改是由某个用户进行的,和/或其他条件(例如日期范围约束)。 IE:

db.items.find(
  {
    "subcategory": "Programming Languages",
    "name": { "$exists": true },
    "change.0.who": "ATL User",
    "change.0.when": { "$gt": new Date("2018-04-01") }
  },
  { "change": { "$slice": 1 } }
)

在这里注意到类似的东西"change.-1.when"是一个非法语句,这基本上就是我们重新排序数组的原因,以便您可以使用legal 0 for first代替-1 for last.

结论

因此,您可以执行多种不同的操作,可以使用聚合方法来过滤数组内容,也可以在对数据的实际存储方式进行一些修改后通过标准查询表单。使用哪一种取决于你自己的情况,但需要注意的是,任何一种标准查询表格将比通过聚合框架或任何计算运算符进行的任何操作运行得快得多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

返回具有最大子文档的文档 的相关文章

随机推荐

  • 如何将 Java Pojo 转换为 Nashorn Json?

    我有一个 Java 对象 我想将其转换为 json 对象并传递给 Nashorn javascript 引擎 谷歌搜索这个问题的答案是非常困难的 有人可以告诉我该怎么做吗 我试过这个 ObjectMapper mapper new Obje
  • javascript正则表达式删除括号中的尾随数字

    我如何替换 追加something 22 字符串到something 使用某种匹配某物的表达式不是常量 它总是不同的 但部分 整数 总是相同的 干杯 EDIT 我发现这有点令人困惑 对我来说也是如此 这就是我的意思 我有一个字符串 一个词
  • 如何在 Android UI 中设置布局背景

    我是 Android 编程新手 我有一个带有一些的用户界面TextView and Button控制 如何在这些组件后面设置背景 我们称之为background png 在您的父布局元素中 例如线性布局或其他 只需添加android bac
  • 解释如何在 Rails 中利用 order 子句

    我很难理解这一部分是如何从这个网站关于 Rails SQL 注入 http rails sqli org resources works 在 ORDER BY 子句中利用 SQL 注入很棘手 但 CASE 语句可用于测试其他字段 将排序列切
  • 使用 Azure Active Directory 访问 Azure Function 时,Blazor 客户端出现 CORS 错误

    我已经尝试部署 Blazor PWA 两天了 到目前为止没有任何成功 如果有人知道我做错了什么 我将非常感激 你好 我可以自己解决大部分问题 但现在使用 AAD 遇到了 CORS 问题 这是我的项目设置 Blazor WebAssembly
  • 查找无序字谜对子串的数量

    我正在尝试解决以下问题 https www hackerrank com challenges sherlock and anagrams https www hackerrank com challenges sherlock and a
  • Web 应用程序编译错误 - ASP.NET 参考

    我当前的 Web 应用程序在本地和实时运行良好 我当前正在使用 Visual Studio 选项 添加 Web 部署项目 编译我的 Web 应用程序 以便所有后面的代码都编译到 DLL 中 有一个特定的构建错误我无法摆脱 错误 50 命名空
  • 为了清晰起见,重构嵌套 IF 语句[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我想重构这个繁琐的方法以使其更具可读性 它有太多我喜欢的嵌套 IF 你会如何重构这个 public static void HandleUplo
  • CQRS - 是否允许从写入端调用读取端?

    我开始阅读有关 CQRS 的内容 但我有点困惑 是否允许在写入端调用读取端来获取附加信息 http cqrs nu Faq command handlers http cqrs nu Faq command handlers在这里他们说这是
  • 将 Postgres \i 输入的输出放入文件?

    快速问题 我希望 如果我使用 i 将输入文件输入 psql 我可以将查询的输出保存到文件中吗 如果是这样 怎么办 谢谢 Using o正如其他人所推荐的 是一个很好的解决方案 不过 只是为了好玩 另一种方法是将输入文件通过管道传输到psql
  • Facebook Messenger 客户聊天插件在未登录时不显示

    我已在我们的网站之一上集成了 Facebook 客户插件 我按照开发人员文档中的说明进行操作 当有活跃的 Facebook 会话时 它工作正常 但是 当没有活动的 Facebook 会话时 该插件根本不会出现 我可能错过了一些东西 但我不知
  • React Native listview:当行到达底部时如何将行粘在屏幕底部

    Using stickyHeaderIndices Ref 粘性标题索引 https facebook github io react native docs listview html stickyheaderindices 在 Reac
  • 将文件设置保存在 ini 而不是注册表中

    我是 MFC 新手 在 myApp InitInstance 中创建第一个应用程序后 我有 SetRegistryKey T Local AppWizard Generated Applications 我可以删除它并将设置保存到我自己的
  • 如何在 html/css 中将图像旁边的文本垂直居中?

    在 html 中将图像旁边的文本垂直居中的最佳和最简单的方法是什么 需要与浏览器版本 类型无关 纯 html CSS 解决方案 这可能会让你开始 http phrogz net CSS vertical align index html 我
  • C++ 中有“byte”数据类型吗?

    如果存在 是否需要包含头文件 此代码会导致编译错误 int main byte b 2 error 不 没有所谓的类型 byte 在 C 中 你想要的是unsigned char 或者 如果您正好需要 8 位 uint8 t from
  • 从 Fortran 中读取 C++“Hello World”

    我正在尝试验证一个用 c 编写的简单的 hello world 函数可以从 FORTRAN 脚本 gfortran 4 9 20 调用 我对 c 和 FORTRAN 都没什么经验 所以我认为这是我应该开始的 code cpp include
  • 使用 ImageView 快速连续显示多张图像

    我有一个应用程序 在一个窗口中 有一个 NSImageView 用户应该能够将任何文件 文件夹 不仅仅是图像 拖放到图像视图中 因此我对 NSImageView 类进行了子类化以添加对这些类型的支持 我选择 NSImageView 而不是普
  • 如何使用 Unix join 获取外连接中的所有字段?

    假设我有两个文件 en csv and sp csv 每个包含恰好两个逗号分隔的记录 en csv 1 dog red car 3 cat white boat sp csv 2 conejo gris tren 3 gato blanco
  • 如何将一个文档中的数组值映射到另一个文档并显示在结果中

    我是 Couchbase 的新手 已经尝试了几个小时了 已查看文档但无法找到这个特定场景 我的存储桶中有文档 type order order id 1 products product id 1 qty 10 product id 2 q
  • 返回具有最大子文档的文档

    我试图根据日期值返回一个包含最大子文档的文档 到目前为止 我能够创建正确的对象 但是查询返回所有子文档而不是具有最大日期的子文档 例如 我的数据存储为 value 1 id 5cb9ea0c75c61525e0176f96 name Tes