使用作为参数传递给 momentjs 的另一个位置字段更新 mongodb 位置字段
Update mongodb positional field with another positional field passed as parameter into momentjs
我正在尝试更新数组中的所有文档。我查看了位置运算符 $[],但问题是我正在尝试使用传递给日期库 momentjs 的先前值更新该字段。
我尝试但失败的查询是
await collection.update(
{},
{
$set: {
'activities.$[].duration.startTime': moment(
'activities.$[].duration.startTime',
'DD/MM/YYYY HH:mm:ss',
).toISOString(),
},
},
{ multi: true },
);
这会将 startTime
字段设置为空。所以我的问题是如何将 activities.$[].duration.startTime
的现有值传递给矩函数。
示例文档(现有)
{
"_id": {
"$oid": "6030b9244991b3001c678492"
},
"activities": [{
"effort": null,
"duration": {
"startTime": "19/01/2021 20:11:35",
"endTime": "19/01/2021 20:15:15",
},
}],
"userId": "5fc8c7504b26e66f676ea50d",
"workoutPlanCode": "",
}
预期输出:
{
"_id": {
"$oid": "6030b9244991b3001c678492"
},
"activities": [{
"effort": null,
"duration": {
"startTime": "2021-01-19T20:58:49.010Z",
"endTime": "2021-01-19T20:58:49.010Z",
},
}],
"userId": "5fc8c7504b26e66f676ea50d",
"workoutPlanCode": "",
}
OP 提到了 1 次 activity。
运行 此查询来自 shell 或 Robomongo
执行查找查询过滤记录 activities
在那里,获取游标并转换为 toArray,循环检查记录是否存在 startTime
将其转换为日期。
function convertToDate (date) {
if (!date.split || date.split('/') < 1) return date; // if it's already date type ignore.
date = date.split('/');
var month = date[1];
var day = date[0]
date[0] = month;
date[1] = day;
return new Date(date);
}
db.data2.find({ activities: { $exists: true } }).toArray().forEach(function (doc) {
doc.activities.forEach(function (d) {
if (d.duration) {
if (d.duration.startTime) {
d.duration.startTime = convertToDate(d.duration.startTime);
}
if (d.duration.endTime) {
d.duration.endTime = convertToDate(d.duration.endTime);
}
}
});
// print(doc); // to validate just perform print and comment save part
db.data2.save(doc); // save the document back
});
首先 - 在更新语句中一般无法使用 momentjs 库和 javascript。
可以使用 v4.2 中提供的 aggregation pipeline 使用从文档本身计算的值来更新字段。
要更新数组中的项目,您需要使用 $map 迭代和更新单个子文档。
最后,针对这个问题,moment的一些功能可以使用date expression operators来实现。
整个查询将是:
db.collection.update({},
[
{
"$set": {
"activities": {
"$map": {
input: "$activities",
as: "a",
in: {
$mergeObjects: [
"$$a",
{
duration: {
startTime: {
$dateToString: {
date: {
$dateFromString: {
dateString: "$$a.duration.startTime",
format: "%d/%m/%Y %H:%M:%S",
onError: null
}
},
format: "%Y-%m-%dT%H:%M:%S.000Z",
onNull: "$$a.duration.startTime"
}
},
endTime: {
$dateToString: {
date: {
$dateFromString: {
dateString: "$$a.duration.endTime",
format: "%d/%m/%Y %H:%M:%S",
onError: null
}
},
format: "%Y-%m-%dT%H:%M:%S.000Z",
onNull: "$$a.duration.endTime"
}
}
}
}
]
}
}
}
}
}
],
{
"multi": true
})
注意事项:
- 如果字符串格式不正确或格式不正确,从字符串到日期的转换可能会出错。在这种情况下,原始字符串将被保留。
- 原始日期没有时区,假定为 UTC
- 原始日期没有毫秒,假设为000
- 建议将日期保留为数据库中的日期,并在表示层上转换为字符串。
我正在尝试更新数组中的所有文档。我查看了位置运算符 $[],但问题是我正在尝试使用传递给日期库 momentjs 的先前值更新该字段。 我尝试但失败的查询是
await collection.update(
{},
{
$set: {
'activities.$[].duration.startTime': moment(
'activities.$[].duration.startTime',
'DD/MM/YYYY HH:mm:ss',
).toISOString(),
},
},
{ multi: true },
);
这会将 startTime
字段设置为空。所以我的问题是如何将 activities.$[].duration.startTime
的现有值传递给矩函数。
示例文档(现有)
{
"_id": {
"$oid": "6030b9244991b3001c678492"
},
"activities": [{
"effort": null,
"duration": {
"startTime": "19/01/2021 20:11:35",
"endTime": "19/01/2021 20:15:15",
},
}],
"userId": "5fc8c7504b26e66f676ea50d",
"workoutPlanCode": "",
}
预期输出:
{
"_id": {
"$oid": "6030b9244991b3001c678492"
},
"activities": [{
"effort": null,
"duration": {
"startTime": "2021-01-19T20:58:49.010Z",
"endTime": "2021-01-19T20:58:49.010Z",
},
}],
"userId": "5fc8c7504b26e66f676ea50d",
"workoutPlanCode": "",
}
OP 提到了 1 次 activity。
运行 此查询来自 shell 或 Robomongo
执行查找查询过滤记录 activities
在那里,获取游标并转换为 toArray,循环检查记录是否存在 startTime
将其转换为日期。
function convertToDate (date) {
if (!date.split || date.split('/') < 1) return date; // if it's already date type ignore.
date = date.split('/');
var month = date[1];
var day = date[0]
date[0] = month;
date[1] = day;
return new Date(date);
}
db.data2.find({ activities: { $exists: true } }).toArray().forEach(function (doc) {
doc.activities.forEach(function (d) {
if (d.duration) {
if (d.duration.startTime) {
d.duration.startTime = convertToDate(d.duration.startTime);
}
if (d.duration.endTime) {
d.duration.endTime = convertToDate(d.duration.endTime);
}
}
});
// print(doc); // to validate just perform print and comment save part
db.data2.save(doc); // save the document back
});
首先 - 在更新语句中一般无法使用 momentjs 库和 javascript。
可以使用 v4.2 中提供的 aggregation pipeline 使用从文档本身计算的值来更新字段。
要更新数组中的项目,您需要使用 $map 迭代和更新单个子文档。
最后,针对这个问题,moment的一些功能可以使用date expression operators来实现。
整个查询将是:
db.collection.update({},
[
{
"$set": {
"activities": {
"$map": {
input: "$activities",
as: "a",
in: {
$mergeObjects: [
"$$a",
{
duration: {
startTime: {
$dateToString: {
date: {
$dateFromString: {
dateString: "$$a.duration.startTime",
format: "%d/%m/%Y %H:%M:%S",
onError: null
}
},
format: "%Y-%m-%dT%H:%M:%S.000Z",
onNull: "$$a.duration.startTime"
}
},
endTime: {
$dateToString: {
date: {
$dateFromString: {
dateString: "$$a.duration.endTime",
format: "%d/%m/%Y %H:%M:%S",
onError: null
}
},
format: "%Y-%m-%dT%H:%M:%S.000Z",
onNull: "$$a.duration.endTime"
}
}
}
}
]
}
}
}
}
}
],
{
"multi": true
})
注意事项:
- 如果字符串格式不正确或格式不正确,从字符串到日期的转换可能会出错。在这种情况下,原始字符串将被保留。
- 原始日期没有时区,假定为 UTC
- 原始日期没有毫秒,假设为000
- 建议将日期保留为数据库中的日期,并在表示层上转换为字符串。