以下架构仅用于记录特定日期的总观看次数和观看次数。
const usersSchema = new Schema({
totalProductsViews: {type: Number, default: 0},
productsViewsStatistics: [{
day: {type: String, default: new Date().toISOString().slice(0, 10), unique: true},
count: {type: Number, default: 0}
}],
});
因此,今天的视图将存储在不同于昨天的另一个子文档中。为了实现这一点,我尝试使用upsert,以便在查看产品的每一天都会创建子文档,并且计数将基于特定的一天进行递增和记录。我尝试使用以下功能,但似乎无法按我预期的方式工作。
usersSchema.statics.increaseProductsViews = async function (id) {
//Based on day only.
const todayDate = new Date().toISOString().slice(0, 10);
const result = await this.findByIdAndUpdate(id, {
$inc: {
totalProductsViews: 1,
'productsViewsStatistics.$[sub].count': 1
},
},
{
upsert: true,
arrayFilters: [{'sub.day': todayDate}],
new: true
});
console.log(result);
return result;
};
我想得到我想要的功能会错过什么?任何帮助将不胜感激。
实际上,您在这里尝试做的事情需要您了解一些可能尚未掌握的概念。两个主要的是:
您不能将任何位置更新用作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
由于同时该操作
仅 适用于“更新插入”操作,它不会从发生妨碍其他操作。
因此,逻辑步骤可以归结为代码中的注释所描述的内容:
尝试匹配文档包含 现有 数组元素的位置,然后更新该元素。使用$inc
在这种情况下,
尝试匹配 文档存在 但 不存在 array元素的 位置 ,然后$push
使用给定日期的默认值匹配一个新元素,count
适当地更新其他元素
如果 您确实确实打算 升迁文档 (而不是数组元素,因为上面是上述步骤),那么 最后 实际上是尝试升迁以创建包括新数组的新属性。
最后是问题bulkWrite()
。尽管这是对服务器的
单个 请求,并且具有 单个
响应,但实际上仍然是三个(如果需要的话,则是两个)操作。没有办法解决这个问题,它比使用findByIdAndUpdate()
甚至发出链式分离的请求要好updateOne()
。
当然,从您尝试实现的代码角度来看,主要的 操作 差异是该方法 不会返回 修改后的文档。根本无法从任何“批量”操作中获得“文档响应”。
这样,实际的“批量”处理将仅使用基于所提供的逻辑以及最重要的是这些语句的 顺序* 提交的三个语句 之一
来修改文档。但是,如果您实际上想在修改后 “返回文档” ,那么唯一的方法就是 单独 请求获取文档。 *
这里唯一需要说明的是,由于读取和更新是分开的,因此除了“数组更新”之外,对文档进行的其他修改的 可能性很小
。实际上,如果没有将三个单独的请求“链接”到服务器,然后确定哪个 “响应文档” 实际应用了您想要实现的更新,则实际上是没有办法的。
因此,与这种情况下它通常被认为是 邪恶的较小 单独做读取。这不是理想的选择,但它是一堆不好的东西中最好的选择。
最后一点,我 强烈建议
实际上将该day
属性存储为BSON日期而不是字符串。实际上,它需要较少的字节来存储,并且以这种形式有用得多。因此,以下构造函数可能是最清晰,最少的hacky:
const todayDate = new Date(new Date().setUTCHours(0,0,0,0))
本文向大家介绍mongodb 修改器($inc/$set/$unset/$push/$pop/upsert),包括了mongodb 修改器($inc/$set/$unset/$push/$pop/upsert)的使用技巧和注意事项,需要的朋友参考一下 对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能够高效的进行文档更新。更新修改器是中特殊的键, 用来指定复杂的操作
b)“Units”字段包含带有“period”字段的子文档(日期对象数组),其中给定的日期位于数组中的第一和第二元素之间。 数据结构如下所示: 我尝试使用.find()和.aggregate()的各种组合,例如在periol数组上使用$project和$filter,在unit._id上使用$elemmatch之后使用$elemmatch,但是没有用--我得到了诸如“不能在数组上使用$filter
给出了一个由N个整数组成的数组。 数组的最大和是该数组的非空连续子数组的元素的最大和。 例如,数组[1,-2,3,-2,5]的最大和是6,因为子数组[3,-2,5]的和是6,并且不可能实现更大的子数组和。 现在,您只能从给定数组中删除一个以上的元素。这样做可以得到的结果数组的最大可能最大和是多少? 我正在用我自己的测试用例测试我的代码。我在Dev-C++上得到了正确的输出。但是当我在网上测试我的代
我正在尝试从MongoDB中的数组中获取一个元素。我认为聚合过滤器是正确的应用程序。但是我已经尝试了一百万次,我仍然找不到问题所在。你能帮我吗? MongoDB示例数据: 我的解决方案: 我的结果: 预期结果: 我已经检查了Mongo参考:https://docs.mongodb.com/manual/reference/operator/aggregation/filter/#example M
我是新来的mongo。我有以下收藏。 文件: 请求: 文档集合中的typeId是文档类型的id,其中请求中的typeId是也可以为空的外部字段。如何获得以下输出。
我有一份这样的文件 上面的文档可以这样概括如下,便于理解。 我需要增加nums子文档中数量的值,该值位于产品子文档中,基于其\u id。 这是我迄今为止所尝试的,但它不起作用,因为我不知道如何捕获nums对象内的\u id,以便更新子子文档数组中的特定对象。 我怎样才能做到这一点?