简体   繁体   English

如何动态更新mongodb中的嵌套对象

[英]how to dynamically update the nested objects in mongodb

We have some arbitrarily nested configuration that we store in the mongodb.我们有一些任意嵌套的配置存储在 mongodb 中。

  1. Let say we initially store the following object in the mongodb.假设我们最初将以下对象存储在 mongodb 中。

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

collection.insertOne({userId, value})

now I want to modify the object in the database by adding现在我想通过添加来修改数据库中的对象

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

and similarly with few more nested object.类似的还有更多的嵌套对象。

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

As we adding, these keys are very dynacmic and should able to update value in the db but not replace it, so expecting the end result stored should be正如我们添加的那样,这些keys是非常动态的,应该能够更新数据库中的值但不能替换它,因此期望存储的最终结果应该是

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

console.log(result);

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

And also overwrite if the udpate value is如果 udpate 值为

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

expected result is预期结果是

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

Similarly when deleting删除的时候也一样

    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: {} }`

Remove method used使用的删除方法

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 });
            }
        });
    });
}

The difficulty here is that you have to convert your objects into MongoDB's dot notation which can be used to build your update statements.这里的困难在于您必须将对象转换为 MongoDB 的点表示法,它可用于构建更新语句。 You can do that by running below function:您可以通过运行以下函数来做到这一点:

 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 });

The reason why you can't run $set directly on your objects is that it will replace existing a nested object instead of merging it.不能直接在对象上运行$set的原因是它将替换现有a嵌套对象而不是合并它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM