Tips for effectively storing and accessing a user's data in MongoDB

Iā€™m a newcomer to Express and currently working on developing an application that can store and retrieve user notes in MongoDB based on their username. My current method involves creating a user object and saving their notes as an array.

Below is the code snippet from my expressJS implementation:

router.post('/editnotes', async (req, res) => {
    const data = req.body
    const { username } = req.query;
    const findUserNotes = await Note.findOne({ username: username })
    if (findUserNotes) {
        findUserNotes.notes.push(data)
        findUserNotes.save()
        res.status(201).send('ok here')
    }
    if (!findUserNotes) {
        const note = new Note({
            username: username,
            notes: [data]
        })
        await note.save()
        res.status(200).send('ok here')
    }
})

Shown below is how it appears in MongoDB Compass:

  "username": "Dhruv70",
  "notes": [
    {
      "topic": "hello",
      "content": "world"
    },
    {
      "topic": "bye",
      "content": "universe"
    },
    {
      "topic": "xxxxxxx",
      "content": "xx"
    }
  ],
  "__v": 31
}

Although the current method works, I believe there could be a more efficient solution for storing and managing data, as performing operations like adding, deleting, or editing elements in the array might become cumbersome over time. Are there any alternative methods worth exploring?

Answer ā„–1

My perspective differs from the other responses, so I've decided to outline my own thoughts here.

  1. To handle your current scenario, you can execute an upsert in a single operation using an update with an aggregation pipeline.
db.collection.update({
    "username": "Dhruv70"
  },
  [{
    "$set": {
      "notes": {
        $concatArrays: [
          {
            $ifNull: ["$notes", []]
          },
          [
            {
              "topic": "new note",
              "content": "to insert"
            }
          ]
        ]
      }
    }
  }],
  {
    upsert: true
  })

Mongo Playground demonstrating a match
Mongo Playground without a match


  1. Another viewpoint suggests reconsidering your schema. This could be valid, but it largely depends on your specific use case. If you find the complexity of the aforementioned update manageable, sticking with the current schema might work. However, if you frequently interact at the notes level, storing notes as individual documents might be more efficient than array entries.

In general, NoSQL tends to prefer denormalizing data over adhering to a traditional entity-relationship model. Some NoSQL databases don't support join/lookup operations. For further insights on MongoDB data modeling, refer to this official MongoDB documentation.

For your present use case, should you opt to convert notes into individual documents, consider this schema:

{
    "topic": "hello",
    "content": "world",
    "username": "Dhruv70",
    "__v": 31
    // additional fields from original user level
},
{
    "topic": "bye",
    "content": "universe",
    "username": "Dhruv70",
    "__v": 31
    // additional fields from original user level
},
{
    "topic": "xxxxxxx",
    "content": "xx",
    "username": "Dhruv70",
    "__v": 31
    // additional fields from original user level
}

You'll notice that user information is duplicated across various notes, illustrating denormalization.

Pros:

  1. The username field can be indexed for quicker lookup and note updates.
  2. Simplified query complexity, enabling updating of notes in a single update operation.
  3. Avoidance of expensive lookups, which are discouraged in MongoDB.

Cons:

  1. If substantial work occurs at the user level, managing duplication/inconsistency of user data may be necessary.
  2. Additional storage required for extra user data.

Like many design challenges, there's no definitive right or wrong answer for data modeling dilemmas. It often involves weighing the pros and cons of different strategies. The above suggestions are based on the details provided thus far.

Answer ā„–2

In my opinion, updating a user note may require two operations and there is no need to create a new collection for it. MongoDB provides support for array operations, as shown in the example below:

First step is to find the note:

const data = req.body;
const note = await Note.findOne({ username });
await Note.findByIdAndUpdate(note._id, {
 notes: {
  $push: data
 }
});

It's better to separate the creation and editing of notes into different routes, such as /create-note and /edit-note.

I believe this information could be useful for you.

Answer ā„–3

Acknowledging your correctness, it is evident that the current solution may not be optimal in the long run. While the initial method suffices for now, scalability could become an issue as the array expands.

It's worth noting that MongoDB's efficiency declines with extensive modifications to large arrays, making tasks like updating individual notes within an array quite cumbersome.

To address this challenge, a more efficient and scalable approach would involve creating distinct collections for users and notes. Subsequently establishing a relationship between the two by referencing the user (e.g., username or user ID) in the notes collection.

This model enables MongoDB to effectively index and query notes, simplifying operations such as addition, deletion, or modification of specific notes.

I hope this clarifies your query.

An analogous example structure would be:

Users

{
  "collection": "users",
  "description": "This collection contains user details.",
  "fields": {
    "_id": {
      "type": "ObjectId",
      "description": "Unique identifier generated by MongoDB."
    },
    "username": {
      "type": "String",
      "description": "Distinct username for each user."
    },
    "email": {
      "type": "String",
      "description": "Optional email address of the user."
    },
    "createdAt": {
      "type": "Date",
      "description": "Creation timestamp of the user account."
    }
  },
  "exampleDocument": {
    "_id": "ObjectId('64f7ca1e4f0b8c8d2a9e57e6')",
    "username": "Dhruuv70",
    "email": "example@email.com",
    "createdAt": "ISODate('2024-10-25T12:34:56Z')"
  }
}

Notes Structure:

{
  "collection": "notes",
  "description": "This collection stores individual notes. Each note references a user from the 'users' collection using 'user_id'.",
  "fields": {
    "_id": {
      "type": "ObjectId",
      "description": "Unique identifier for each note created by MongoDB."
    },
    "user_id": {
      "type": "ObjectId",
      "description": "Refers to the user who owns the note; linked to 'users' collection '_id' field."
    },
    "topic": {
      "type": "String",
      "description": "Title or topic of the note."
    },
    "content": {
      "type": "String",
      "description": "Body content of the note."
    },
    "createdAt": {
      "type": "Date",
      "description": "Timestamp of note creation."
    }
  },
  "exampleDocument": {
    "_id": "ObjectId('74b9ca1e4f0b8c8d2a9e57e7')",
    "user_id": "ObjectId('64f7ca1e4f0b8c8d2a9e57e6')",
    "topic": "hello",
    "content": "world",
    "createdAt": "ISODate('2024-10-25T12:34:56Z')"
  }
}

Now, updating a single note can be done using its corresponding _id, while retrieving all notes belonging to a user involves querying the notes collection with the respective user_id.

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

Assigning a value to a variable from a method in Vue: a step-by-step guide

I'm having trouble assigning values from a method to variables in HTML. Here's what I have in my code: <b-card-text>X position {{xpos}}</b-card-text> <b-card-text>Y position {{ypos}}</b-card-text> I would like to assign v ...

Changing environment variables for jasmine tests

My Angular service code snippet includes importing the environment like this: import {environment} from '../environment' .... public something() { if(environment.production) { // do stuf } else { // do something else } } I am now l ...

Using JQuery to Retrieve JSON Data from an HTTPS Endpoint

I am attempting to retrieve a JSON file from an https secured website without using server-side languages. The client specifically requested that the process be entirely implemented in JavaScript. After some research, I discovered that I need to utilize J ...

Is there a button that allows updating the text in a search field by entering multiple values one after the other?

Is it possible to insert multiple values sequentially into the search field using the same button? For example: value 1, value 2, value 3... Check out a demo here <form id="form1" name="form1" method="post"> <p> <input type=" ...

Importing types from a private npm module with FlowTypes

Currently I am in the process of developing a private npm package for internal use. One challenge I am facing is how to include flowtypes that can be shared across different internal projects. Ideally, I would like these flowtypes to be imported in the for ...

Is it possible to divide a column in an HTML table into two separate

I am currently working with an array of elements that I need to iterate over. For each element, I create a <td></td> tag. When dealing with 10 elements, it results in a table with one column and 10 rows. Is there a method, using either HTML o ...

React-Native 0.1.17 Navigator Bar: Enhancing User Navigation Experience

An issue arose after upgrading my react-native 0.1.15 app to version 0.1.17 - I'm now encountering an 'Unable to download JS bundle error'. Upon investigation, I found the error in my code: var SportsSocial = React.createClass({ component ...

What is the best way to split two sets of radio buttons with the same name into distinct blocks in an HTML form?

For my project, I am working with two sets of radio buttons where the values are stored in a Database. Depending on another result in the HTML form, I need to display one set of radio buttons or the other. The issue arises when using the same name for all ...

Is there a way to search for a specific item within a nested array?

I have 2 arrays within an array, each containing objects. How can I locate the object with the name "Sneijder"? const players = [ [ { id: 1, name: "Hagi", }, { id: 2, name: "Carlos", }, ], [ { id: 3 ...

Transfer information through req.body from one HTML file to another using Express

I'm having an issue with importing data from a form page on my express server. Currently, the home get request leads to a form page and after submitting the form, the data is stored in req.body as a JSON. I can successfully log this information to th ...

What is the best way to refresh or manually trigger the marker cluster icon update in Google Maps API?

Recently, I implemented a custom cluster HTML marker, where I attempted to dynamically change the color of my markers within the cluster. Despite debugging the code and confirming that the color variable was being updated correctly, the marker colors thems ...

Error: The function props.addToCart is not accessible

While attempting to trigger my action on the client's click of the "addToCart" button to add a new product to the cart, I encountered the error message: "TypeError: props.addToCart is not a function." I am relatively new to Redux and have grasped the ...

Discovering which chip has wrapped to the next line in Material UI Autocomplete can be found by closely inspect

Currently, I am working with a Material UI autocomplete feature that functions as follows: https://i.sstatic.net/4LrwI.png My goal is to determine when the fourth chip wraps to the next line within the autocomplete so that I can proceed with additional c ...

What situations warrant the choice of an Isomorphic JavaScript application?

Recently, there has been an increase in tutorials and examples discussing Isomorphic web applications with react.js. As a beginner myself, I find it challenging to determine whether this is necessary or not. For instance, my application will primarily be ...

What is the best way to separate the back-end and front-end on a single domain?

I have developed my application using React and Node.js (Express) and I am hosting it on Heroku. I am hosting it under the same domain to ensure proper cookie functionality as I encountered some issues in the past. The problem arises when I navigate to www ...

The functionality of $nin in mongoDB seems to be malfunctioning

I am in the process of designing a new social networking platform and have created a User Schema that includes an array of strings called user.friends_list. However, when I execute the code, the outcome is not as expected. It returns only some of the membe ...

Storing form information within the view

What is the best way to transfer data between views in AngularJS? I tried using $rootScope but it's not working as expected. ...

Unable to generate a file using fs.appendFile in Node.js

For some time now, I've been working on a program that is meant to save logs from a Slack team. I've managed to get most things working, but I've hit a roadblock with using fs.appendFile() successfully. The documentation states that it shoul ...

Converting Java data to JSON using a Jquery script

Does anyone know of a jQuery method that can convert a Java data object into JSON format? I am currently utilizing the HTTPResponse object to deliver my object to my ajax, but it is returning a String object. Note: JSON.parse is not an option and I am una ...

What is the best approach to simultaneously update an array using multiple threads in a Node.js environment?

Hey there, I'm trying to figure out how to make changes to the same array using 2 worker threads in Node.js. Can anyone help me with this? My issue is that when I add a value in worker thread 1 and then try to access it in worker thread 2, the second ...