【问题标题】:how to dynamically update the nested objects in mongodb如何动态更新mongodb中的嵌套对象
【发布时间】:2020-01-28 23:21:19
【问题描述】:

我们有一些任意嵌套的配置存储在 mongodb 中。

  1. 假设我们最初将以下对象存储在 mongodb 中。

const value = { 'a': { 'b': 1 } }

collection.insertOne({userId, value})

现在我想通过添加来修改数据库中的对象

const addValue = { 'f': { 'c': 2 } }

类似地,还有更多的嵌套对象。

const addValue1 = { 'a': { 'd': 1 }, 'f': { 'g': 1 } };

正如我们添加的那样,这些keys 非常动态,应该能够更新数据库中的值但不能替换它,因此期望存储的最终结果应该是

const result = collection.findOne({ userId });

console.log(result);

{ 'a': { 'b': 1, 'd': 1 }, 'f': { 'g': 1, 'c': 2 } }

如果 udpate 值是也覆盖

const addValue2 = { 'a': { 'b' : { 'e': 1 } } }

预期结果是

const result2 = { 'a': { 'b': { 'e': 1 } , 'd': 1 }, 'f': { 'g': 1, 'c': 2 } }

删除时也一样

    let testObject = new MongoDBStorageService('test', dbConnection as any, 'userTestSchema');

    testObject.load({ 'a': { 'b': 1 }});
    testObject.removeValue('a.b');

    const content = await testObject.contents;

 expect(content).toEqual({}); // but we see output as `{ a: {} }`

删除使用的方法

public async removeValue(key: string) {
        return await this.remove(JSON.parse(`{\"${key}\": "" }`));
    }
private remove(value) {
    return new Promise((resolve, reject) => {
        this.collection.updateOne({ user: this.userId }, {
            $unset: value,
        }, { upsert: false }, function (err, res) {
            if (err) {
                reject(err);
            } else {
                console.log('REUSLL AFTER REMOVE', res.);
                resolve({ id: true });
            }
        });
    });
}

【问题讨论】:

    标签: javascript mongodb mongodb-query


    【解决方案1】:

    这里的困难在于您必须将您的对象转换为 MongoDB 的点符号,该符号可用于构建您的更新语句。您可以通过运行以下函数来做到这一点:

    let flatten = (obj, prefix, result) => {
        result = result || {};
        for(let key of Object.keys(obj)){
            let keyExpr = prefix  ? `${prefix}.${key}` : `${key}`;
            if(typeof obj[key] === "object"){
                flatten(obj[key], keyExpr, result);
            } else {
                result[keyExpr] = obj[key];
            }
        }
        return result;
    }
    
    const addValue = { 'f': { 'c': 2 } }
    let update1 = flatten(addValue)
    console.log(update1);
    
    const addValue1 = { 'a': { 'd': 1 }, 'f': { 'g': 1 } };
    let update2 = flatten(addValue1);
    console.log(update2);
    const value = { 'a': { 'b': 1 } }
    const userId = 1;
    db.col.insertOne({userId, ...value})
    
    db.col.update({ userId: userId }, { $set: update1 });
    db.col.update({ userId: userId }, { $set: update2 });
    

    您不能直接在对象上运行$set 的原因是它将替换现有的a 嵌套对象而不是合并它。

    【讨论】:

    • 有道理让我快速测试一下
    • @user1595858 测试进展如何 :) ?
    • 在增加价值方面做得很好。但是删除有问题。
    • @user1595858 最初没有提到有任何删除。我可以稍后看看:-)
    • @user1595858 关于您的删除示例:无论何时运行updateOne,您都不知道a 字段的状态。您只需取消设置您知道的密钥 a.b,但您不知道是否有 a.ca.d 等。您所能做的就是运行 $unset 并稍后以某种方式处理空对象。或者,您需要先find 文档,然后在知道它的全部内容的情况下运行更新 - 但这是两次数据库往返,因此您可以决定哪种方式更可取。
    猜你喜欢
    • 2021-01-23
    • 2023-01-12
    • 2021-11-15
    • 2023-04-03
    • 2022-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多