In MongoDB, learn the process of efficiently updating nested objects in a dynamic manner

We have a variety of nested configurations stored in MongoDB.

  1. Initially, we store the following object in MongoDB:

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

collection.insertOne({userId, value})

Now, I would like to modify the object in the database by adding

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

as well as a few more nested objects.

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

As these keys are dynamic and the values should be updated without replacing them, the expected end result stored should be

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

console.log(result);

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

Also, if the update value is to overwrite existing data,

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

the expected result is

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

Similarly, when deleting items

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

A Remove method example

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('RESULT AFTER REMOVE', res.);
                resolve({ id: true });
            }
        });
    });
}

Answer №1

To tackle this issue, it is essential to transform your objects into MongoDB's dot notation, which will enable you to construct your update statements effectively. Achieve this by utilizing the following function:

let flattenObjects = (obj, prefix, result) => {
    result = result || {};
    for(let prop of Object.keys(obj)){
        let keyExpression = prefix ? `${prefix}.${prop}` : `${prop}`;
        if(typeof obj[prop] === "object"){
            flattenObjects(obj[prop], keyExpression, result);
        } else {
            result[keyExpression] = obj[prop];
        }
    }
    return result;
}

const additionalValue = { 'x': { 'y': 2 } };
let updatedObject1 = flattenObjects(additionalValue);
console.log(updatedObject1);

const moreValues = { 'm': { 'n': 1 }, 'x': { 'z': 1 } };
let updatedObject2 = flattenObjects(moreValues);
console.log(updatedObject2);

const item = { 'm': { 'l': 1 } };
const userID = 1;
db.collection.insertOne({userID, ...item})

db.collection.update({ userID: userID }, { $set: updatedObject1 });
db.collection.update({ userID: userID }, { $set: updatedObject2 });

The main reason why applying $set directly on your objects isn't feasible is because it would replace the existing nested object instead of merging it.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering an issue with the autocomplete feature in the jQuery library where it is stating "this.source is not a function."

Here's the code snippet I'm working with: $.ajax({ type: "GET", url: "https://url.com", dataType: "json", success: function (data) { $("#search").autocomplete({ source: data, select: function (even ...

Challenge with Express.js and Mongoose Query

I am facing an issue with querying my MongoDB for a single document using _id. I am working with Mongoose version 4.11.1. The problem arises when I try to run the query by passing the _id as a URL parameter on the route localhost:3000/poi/one/595ef9c8c4891 ...

What could be causing the submenus in my intricate menu component to lose focus when input is entered?

I'm currently working on developing a menu using the MUI Menu component. The goal is to have a popup input control (such as Autocomplete, TextField, Select, or a custom form) appear when a menu item is clicked, based on the choice made from the menu. ...

Receiving multiple NodeJS Responses through AJAX for a single request

I have been working on a WebApp that involves heavy AJAX calls from the frontend and NodeJS Express at the backend. Here is a glimpse of my Frontend Code- Below is the global AJAX function I consistently use in all my projects: function _ajax(params = {}, ...

Utilizing Puppeteer to Navigate and Interact with Elements Sharing Identical Class Names

I am new to Puppeteer and NodeJs, and I am attempting to scrape a specific website with multiple posts that contain a List element. Clicking on the List element loads the comment section. My question is: I want to click on all the list elements (since th ...

Calculate the time difference between the stroke of midnight on a specific date and the present moment using JavaScript, node.js, and

Looking for a way to determine if the current moment is less than 3 minutes after midnight of the next date using a JavaScript Date object (e.g. 09.08.2020 15.45). This condition should evaluate to true for times ranging from 09.09.2020 00:00 up until 09.0 ...

Retrieving input values with JQuery

HTML <td data-title="Quantity"> <div class="clearfix quantity r_corners d_inline_middle f_size_medium color_dark m_bottom_10"> <button class="btn-minus bg_tr d_block f_left" data-item-price="8000.0" data-direction= ...

Troubleshooting a deployment issue with a multi-container Docker application

Currently facing an issue with deploying my application to Amazon's Elastic Beanstalk. The application is a multi-container Docker setup that consists of a node server and mongoDB. Unfortunately, every time I attempt to deploy the application, it cras ...

Guide on creating multiple instances of vue-multiselect with a simple button click

I am trying to implement a vue-multiselect dropdown with the addition of a new dropdown upon clicking an "add more" button. However, I am currently unsure of the best approach to achieve this. Problem/Question: When adding 2 dropdowns, if the same option ...

Determine whether an object exists within another object and merge its value into the formatted object

When filling out a form, I have a formattedData object that holds a deep copy of the original data object. If a field in the form is changed, I must update the formatted data object with properties from the values object. To simulate this scenario, I crea ...

Setting a port in Next.js: A step-by-step guide

I have one application currently running on port 3000 and I need to run another application on a different port in React Next.js. How can I make this change? In my package.json file, the current scripts section looks like this: "scripts": { & ...

How can I retrieve the Google Maps URL containing a 'placeid' using AJAX?

I have a specific URL that I can access through my browser to see JSON data. The URL appears as follows: https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJZeH1eyl344kRA3v52Jl3kHo&key=API_KEY_HERE However, when I attempt to use jQuer ...

Showing a JSON file in an HTML page

I've been attempting to showcase a local JSON file on an HTML page. I stumbled upon some information online, but it's causing me quite a bit of confusion. Here is the JSON file I have: { "activities": [ { "name": "C:&bs ...

Evaluating string combinations in JavaScript using valid comparisons

After choosing values on the screen, two variables store their value. var uval = '100'; var eval = '5'; There are 2 combinations with values: let combination1= 'u:100;e:1,4,5,10' let combination2 = 'u:1000;e:120,400,500, ...

What is the best way to access a specific attribute of an object that is within an array in JavaScript or Google Apps Script?

One challenge I'm facing is with a javascript function that generates an array filled with objects. Each object contains various attributes such as id, colour, and size. After the array is created, it is sent to a Google Apps Script for further proces ...

How to use Express Validator to validate both email and username within a single field?

I am currently developing an application using the Express (Node.js framework) and I want to allow users to log in with either their email address or username. My question is, how can I implement validation for both types of input on the same field using e ...

Error encountered during Ajax request - two files being transmitted instead of one

Can someone assist me with a basic ajax call for a login button? I need help with the form submission and sending the request to a php file to handle the login action. However, I am encountering an issue where two files are being sent instead of one when ...

Difficulty with AngularJS pagination and encountering errors when trying to read the property 'slice' of an undefined value

Could someone please help me with this issue I'm facing? Here is the code snippet: (function () { var app = angular.module('store', ['ui.bootstrap']); app.controller('StoreController', function ($scope, $http) ...

Stopping a recurring setTimeout using an API request: What's the solution?

I have a NextJS application that runs a recursive setTimeout when the server is started. I am looking to create an API endpoint that can control this loop, allowing me to start and stop it as needed in a production environment. This loop specifically proce ...

Creating a JSX.Element as a prop within a TypeScript interface

I need to create an interface for a component that will accept a JSX.Element as a prop. I have been using ReactNode for this purpose, but I am facing issues when trying to display the icon. How can I resolve this issue? export interface firstLevelMenuItem ...