javascript - 根据 id 更新两层嵌套对象
问题描述
我的Mother
模型中有这个结构(这是一个固定结构,我只是在这 3 个数组级别上推送卡片或更新它们):
{
cards: {
starter: [],
intermediate: [],
advanced: [ {Object}, {Object}, {Object} ]
},
}
上面的Objects
内部cards.advanced
数组如下:
{
cards: [
{ // this is a single card object
title: 'this is a card',
id: 'main-2-1' // this is unique id only in advanced array, we may have exact id for a card in starter or in intermediate array
}
],
unit: 2 // this is the unit
}
假设我可以访问这样的Mother
模型:
const motherModel = await db.Mother.findOne({}); // this retrieves all data in the Model
我们如何根据卡片对象及其所属更新id
卡片对象并将level
整个卡片对象替换为newCard
?
const level = 'advanced'; // the level of the card we want to search for
const cardID = 'main-2-1'; // the exact id of the card we want to be replaced
const cardUnit = cardID.split('-')[1]; // I can calculate this as the unit in which the card exist inside
const newCard = { // new card to be replaced
title: 'this is our new updated card',
id: 'main-2-1'
}
我试过这个没有运气:
const updated = await db.Mother.update(
{ ["cards." + level + ".unit"]: cardUnit },
{ ["cards." + level + ".$.cards"]: newCard }
)
我也试过这个,但它并没有改变模型中的任何东西:
async function updateMotherCard(card, level) {
const cardID = card.id;
const cardUnit = cardID.split('-')[1];
const motherModel = await db.Mother.findOne({});
const motherLevel = motherModel.cards[level];
const selectedUnit = motherLevel.find(e => e.unit == cardUnit);
let selectedCard = selectedUnit.cards.find(e => e.id == cardID);
selectedCard = card;
const updated = await motherModel.save();
console.log(updated);
}
解决方案
您实际上可以使用update方法解决您的问题,但如果您使用的是 MongoDB 4.2 或更高版本,则必须以不同的方式进行。第二个参数可以是$set
您要执行的操作或aggregation
管道。使用后者,您可以更自由地塑造数据。这是您解决问题的方法,我将在以下情况下进行分解:
db.collection.update({
"cards.advanced.unit": 2
},
[
{
$set: {
"cards.advanced": {
$map: {
input: "$cards.advanced",
as: "adv",
in: {
cards: {
$map: {
input: "$$adv.cards",
as: "advcard",
in: {
$cond: [
{
$eq: [
"$$advcard.id",
"main-2-1"
]
},
{
title: "this is a NEW updated card",
id: "$$advcard.id"
},
"$$advcard"
]
}
}
},
unit: "$$adv.unit"
}
}
}
}
}
],
{
new: true,
});
首先使用传递三个参数的更新方法:
- 过滤查询
- 聚合管道
- 选项。这里我只是用来
new: true
返回更新后的文档,方便测试。
这是结构:
db.collection.update({
"cards.advanced.unit": 2
},
[
// Pipeline
],
{
new: true,
});
在管道内部,我们只需要一个阶段,用我们将创建的数组$set
替换属性。advanced
...
[
{
$set: {
"cards.advanced": {
// Our first map
}
}
}
]
...
我们首先映射advanced
数组以便能够映射嵌套的卡片数组:
...
[
{
$set: {
"cards.advanced": {
$map: {
input: "$cards.advanced",
as: "adv",
in: {
// Here we will map the nested array
}
}
}
}
}
]
...
我们使用我们在第一个映射中声明的变量,其中包含正在映射的高级数组当前项 ( adv
) 来访问和映射嵌套的“卡片”数组 ( $$adv.cards
):
...
[
{
$set: {
"cards.advanced": {
$map: {
input: "$cards.advanced",
as: "adv",
in: {
cards: {
$map: {
input: "$$adv.cards",
as: "advcard",
in: {
// We place our condition to check for the chosen card here
}
}
},
unit: "$$adv.unit",
}
}
}
}
}
]
...
最后,我们检查当前卡 id 是否等于正在搜索的 id,$eq: [ "$$advcard.id", "main-2-1" ]
如果匹配则返回新卡或当前卡:
...
{
$cond: [
{
$eq: [
"$$advcard.id",
"main-2-1"
]
},
{
title: "this is a NEW updated card",
id: "$$advcard"
},
"$$advcard"
]
}
...
这是所描述内容的工作示例: https ://mongoplayground.net/p/xivZGNeD8ng
推荐阅读
- string - 无抖动的永远在线模式匹配服务
- javascript - 无法在移动视图中隐藏 div
- angular - 在 Angular 7 中覆盖库组件的 HTML 模板
- python - 用函数根据特定分布生成随机数
- python - Python ConfigParser:输入节名称作为变量
- android - 如何一次从 JSON 对象中检索多个项目
- asp.net - log4net 写入“?” 当我使用 %type、%method 和 %line 模式时
- python - 下面的小 x 刻度,上面的主要
- php - 我正在尝试制作这个脚本,但正在向我展示这个问题
- c# - C# - 关闭其他进程的消息框