栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

数组中的Upsert和$ inc子文档

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数组中的Upsert和$ inc子文档

实际上,您在这里尝试做的事情需要您了解一些可能尚未掌握的概念。两个主要的是:

  • 您不能将任何位置更新用作upsert的一部分,因为它需要提供数据

  • 将项目添加到与“ upsert”混合的数组中通常是一个无法在单个语句中完成的问题。

尚不清楚“ upsert”是否是您的实际意图,还是只是为了使您的陈述 生效 而必须添加的内容。如果这是您的意图,它会使事情复杂化,即使 不太可能
给出 暗示 您实际上期望 “文档”
始终存在的

finByIdAndUpdate()
用法。


无论如何,很显然您实际上希望 “找到时更新数组元素,或者在找不到的地方插入新的数组元素” 。实际上,这是 两个 写入过程,当您考虑“
upsert”情况时,则也是 三个 过程。

为此,您实际上需要通过

bulkWrite()
以下方式调用语句:

usersSchema.statics.increaseProductsViews = async function (_id) {  //based on day only.  const todayDate = new Date().toISOString().slice(0, 10);  await this.bulkWrite([    // Try to match an existing element and update it ( do NOT upsert )    {      "updateOne": {        "filter": { _id, "productViewStatistics.day": todayDate },        "update": {          "$inc": { "totalProductsViews": 1, "productViewStatistics.$.count": 1          }        }      }    },    // Try to $push where the element is not there but document is - ( do NOT upsert )    {      "updateOne": {        "filter": { _id, "productViewStatistics.day": { "$ne": todayDate } },        "update": {          "$inc": { "totalProductViews": 1 },          "$push": { "productViewStatistics": { "day": todayDate, "count": 1 } }        }      }    },    // Finally attempt upsert where the "document" was not there at all,    // only if you actually mean it - so optional    {      "updateOne": {        "filter": { _id },        "update": {          "$setOnInsert": { "totalProductViews": 1, "productViewStatistics": [{ "day": todayDate, "count": 1 }]          }        }    }  ])  // return the modified document if you really must  return this.findById(_id); // Not atomic, but the lesser of all evils}

因此,这里有一个很好的理由说明为什么位置过滤

[<identifier>]
运算符不在此处应用。主要的好理由是 预期目的更新多个匹配的数组元素 ,而您只想更新 一个
。实际上,它确实在位置
$
运算符中有一个特定的运算符。但是,正如上面的前两个语句所示,它的条件
必须 包含在 查询谓词
(语句中的
"filter"
属性
UpdateOne
)内
bulkWrite()

因此,使用位置过滤

[<identifier>]
的主要问题在于,正如前两个语句所示,您实际上不能在
$inc
或之间进行切换
$push
,这取决于文档是否实际包含的数组条目
day
。所有这一切会发生是
最好 当电流没有更新将被应用
day
不是由表达式匹配
arrayFilters

最坏
的情况是一个实际的“更新插入”将抛出一个错误,由于MongoDB中不能够从语句破译“路径名称”,当然你根本无法

$inc
东西并不存在,作为一个“新”的数组元素。那
需要
一个
$push

这使得你的机械师,你也 不能
两者都做的

$inc
$push
一个内
单个 语句。如果您尝试将 MongoDB ”修改
为非法操作,MongoDB将会出错。几乎同样适用于
$setOnInsert
由于同时该操作
适用于“更新插入”操作,它不会从发生妨碍其他操作。

因此,逻辑步骤可以归结为代码中的注释所描述的内容:

  1. 尝试匹配文档包含 现有 数组元素的位置,然后更新该元素。使用

    $inc
    在这种情况下,

  2. 尝试匹配 文档存在不存在 array元素的 位置 ,然后

    $push
    使用给定日期的默认值匹配一个新元素,
    count
    适当地更新其他元素

  3. 如果 您确实确实打算 升迁文档 (而不是数组元素,因为上面是上述步骤),那么 最后 实际上是尝试升迁以创建包括新数组的新属性。

最后是问题

bulkWrite()
。尽管这是对服务器的
单个 请求,并且具有 单个
响应,但实际上仍然是三个(如果需要的话,则是两个)操作。没有办法解决这个问题,它比使用
findByIdAndUpdate()
甚至发出链式分离的请求要好
updateOne()

当然,从您尝试实现的代码角度来看,主要的 操作 差异是该方法 不会返回 修改后的文档。根本无法从任何“批量”操作中获得“文档响应”。

这样,实际的“批量”处理将仅使用基于所提供的逻辑以及最重要的是这些语句的 顺序* 提交的三个语句 之一
来修改文档。但是,如果您实际上想在修改后 “返回文档” ,那么唯一的方法就是 单独 请求获取文档。
*

这里唯一需要说明的是,由于读取和更新是分开的,因此除了“数组更新”之外,对文档进行的其他修改的 可能性很小
。实际上,如果没有将三个单独的请求“链接”到服务器,然后确定哪个 “响应文档” 实际应用了您想要实现的更新,则实际上是没有办法的。

因此,与这种情况下它通常被认为是 邪恶的较小 单独做读取。这不是理想的选择,但它是一堆不好的东西中最好的选择。


最后一点,我 强烈建议
实际上将该

day
属性存储为BSON日期而不是字符串。实际上,它需要较少的字节来存储,并且以这种形式有用得多。因此,以下构造函数可能是最清晰,最少的hacky:

 const todayDate = new Date(new Date().setUTCHours(0,0,0,0))


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/436649.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号