首页 > 解决方案 > 如何动态更新mongodb中的嵌套对象

问题描述

我们有一些任意嵌套的配置存储在 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 });
            }
        });
    });
}

标签: javascriptmongodbmongodb-query

解决方案


这里的困难是你必须将你的对象转换成 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嵌套对象而不是合并它。


推荐阅读