как динамически обновлять вложенные объекты в mongodb - PullRequest
1 голос
/ 29 января 2020

У нас есть произвольная вложенная конфигурация, которую мы храним в 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 очень динаммичны c и должны иметь возможность обновлять значение в БД, но не заменять его, поэтому ожидаемый конечный результат должен быть

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

console.log(result);

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

И также перезаписывать, если значение обновления

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

1 Ответ

0 голосов
/ 29 января 2020

Сложность заключается в том, что вам необходимо преобразовать ваши объекты в точечную нотацию 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 вместо слияния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...