mongodb -创建一个视图,从集合中获取每个最近的文档

u1ehiz5o  于 2022-11-22  发布在  Go
关注(0)|答案(2)|浏览(173)

bounty将在3天后过期。回答此问题可获得+50声望奖励。Scuba Steve正在寻找标准答案

我有一个每天从HRIS中提取状态数据的集合。我们可以将状态数据用于各种有趣的事情,比如预测分析。
然而,状态变化数据无限制地增长(目前,这是我们需要解决的另一个技术债务)。我想从创建一个视图开始,该视图只从集合中获取最近的记录。因此,我有以下视图创建代码:

db.rawEmployeeStatus.aggregate().match({dateOfStateCapture:   
                                      db.rawEmployeeStatus.find({})
                                                          .sort({$natural : -1})
                                                          .limit(1)
                                                          .toArray()[0]
                                                          .dateOfStateCapture})      
                                .saveAsView("employeeStatusCurrentState",{dropIfExists:false})

但是,此视图的问题是,它获取 * 在创建视图时 * 的最新记录,然后将该数据用于视图。理想情况下,视图中的数据应始终从集合中的最新记录填充。

8cdiaqws

8cdiaqws1#

如果dateOfStateCapture字段是标识集合中最新文档的字段,则如下视图可能满足您的需要:

db.createView(
  "employeeStatusCurrentState", 
  "rawEmployeeStatus", 
  [
    { $sort: { dateOfStateCapture: -1 } },
    { $limit: 1 }
  ], 
);

或者,假设您对_id字段使用自动生成的ObjectId(其值会增加),则以下视图将满足您的需要:

db.createView(
  "employeeStatusCurrentState", 
  "rawEmployeeStatus", 
  [
    { $sort: { _id: -1 } },
    { $limit: 1 }
  ], 
);

下面是后者工作原理的快速演示:

> db.employeeStatusCurrentState.find()
[ { _id: 3, val: 'c' } ]
>
> db.rawEmployeeStatus.insertOne({ _id: 4, val: 'd' })
{ acknowledged: true, insertedId: 4 }
>
> db.employeeStatusCurrentState.find()
[ { _id: 4, val: 'd' } ]

另一个答案中的视图是静态的说法并不正确。正如那个答案中提到的,有一个页面演示了如何通过$merge物化视图,但这与它们的read-only views无关。这里有一小部分是关于两者之间的比较。
现在,让我们深入了解一下问题中提到的行为和约束的细节。首先,回顾一下评论中的内容:
什么是saveAsView()?
它会创建一个视图...
当然,很明显,这是总体思路。但是这里的细节对于回答你的问题非常重要。什么类型的视图(例如,它是实体化的)以及它是在哪里创建的?例如,如果实用程序正在保存查询的 * 结果 *(缓存/实体化它),
saveAsView()not a helper function provided by MongoDB。官方助手是createView(),因此我提出了这个问题。
通过一些额外的研究,我认为saveAsView()offered by the NoSQLBooster for MongoDB (previously "MongoBooster") utility beginning with version 3.3的功能。我下载并尝试了该实用程序,根据下面的示例,它看起来确实在数据库中创建了一个非物化视图。但该视图定义的细节似乎是造成混乱和麻烦的原因。
按照这些步骤,我从数据库中的这个集合开始:

test> show collections
rawEmployeeStatus
test> db.rawEmployeeStatus.find()
[
  { _id: 1, dateOfStateCapture: 1 },
  { _id: 2, dateOfStateCapture: 2 },
  { _id: 3, dateOfStateCapture: 3 }
]

然后,我在NoSQLBooster(版本7.1.16)中运行与问题完全相同的命令。之后,我可以在数据库中看到视图:

test> show collections
employeeStatusCurrentState  [view]
rawEmployeeStatus

如果我查询它,我会得到一个预期的文档:

test> db.employeeStatusCurrentState.find()
[ { _id: 3, dateOfStateCapture: 3 } ]
test>

正如您提到的,如果我将一个新文档插入到rawEmployeeStatus中,然后再次查询视图,我仍然会得到3_id的前一个文档:

test> db.rawEmployeeStatus.insertOne({_id:4, dateOfStateCapture:4})
{ acknowledged: true, insertedId: 4 }
test> db.employeeStatusCurrentState.find()
[ { _id: 3, dateOfStateCapture: 3 } ]

当我们看一下视图定义时,我们就可以明白为什么:

test> db.getCollectionInfos({name:"employeeStatusCurrentState"})
[
  {
    name: 'employeeStatusCurrentState',
    type: 'view',
    options: {
      viewOn: 'rawEmployeeStatus',
      pipeline: [ { '$match': { dateOfStateCapture: 3 } } ]
    },
    info: { readOnly: true }
  }
]

具体来说,请查看定义视图的pipeline

[ { '$match': { dateOfStateCapture: 3 } } ]

这里发生的情况是,在将命令的内部部分发送到数据库以存储在视图中之前,执行该命令的内部部分以解析为一个值。因此:

db.rawEmployeeStatus.find({})
                                                          .sort({$natural : -1})
                                                          .limit(1)
                                                          .toArray()[0]
                                                          .dateOfStateCapture

解析为3(在我的示例中),并存储在视图定义中。这是由NoSQLBooster客户端执行的,因为类似.toArray()[0]的内容不是有效的聚合语法,因此对于视图中的存储无效。
总而言之,MongoDB中的经典视图 * 不是 * 静态的在你的特殊情况下使用的第三方工具以非显而易见的方式创建了视图。这要求它将一些定义解析为作为视图定义本身的一部分提供的静态值。创建视图的替代语法将满足您的需要(或至少为您指出正确的方向)在此答案的顶部提供。

ovfsdjhp

ovfsdjhp2#

我 可能 是 错 的 , 但 我 的 印象 是 mongo 视图 在 创建 或 刷新 时 总是 静态 的 ( 标准 和 按 需 物化 视图 ) , 这 取决 于 源 聚合 结果 。
如果 您 查看 on-demand materialised views 的 文档 , 通常 会 发现 有 3 个 不同 的 独立 步骤
1.定义 按 需 实体 化 视图
1.执行 初始 运行
1.刷新 实体 化 视图
我 相信 您 希望 在 生成 物化 视图 的 集合 中 有 插入 时 刷新 要 更新 的 物化 视图 。 但是 , 事实 并非 如此 。 物化 视图 本质 上 是 一 个 基于 聚合 的 虚拟 集合 ,它 不 知道 源 集合 更改 的 影响( s ) 个 数据 实体 。 如果 有 就 更 好 了 ! 但 您 的 视图 通常 是 基于 优化 子集 的 , 因此 插入 或 更新 可能 不会 更改 视图 的 ( 例如 , 虚拟 聚合 结果 ) 。
因此 , 为了 在 插入 后 更新 视图 , 必须 始终 执行 刷新 视图 的 最 后 一 步 ( 例如 , 再次 运行 聚合 查询 ) 。 显然 , 在 刷新 后 执行 此 操作 相当 激进 , 而且 性能 肯定 不 高 。
在 维护 最 新 状态 的 视图 的 情况 下 , 可能 需要 一 个 应用 程序 级 回调 , 检查 在 每次 执行 插入/更新 操作 后 是否 有 理由 更新 视图 。 同样 , 这 取决 于 记录 在 您 的 情况 下 的 外观 。 如果 是 一 个 简单 的 文档 筛选 器 ( 因为 所有 更新 都 是 插入 ) ,那么 您 可能 会 在 每次 插入 时 刷新 。 如果 状态 更新 是 在 单个 记录 的 数组 属性 中 , 那么 并非 所有 更新 都 可能 触发 刷新 等 。

相关问题