Issue with reverse document referencing in Mongoose

I've been searching extensively for a way to reference documents bidirectionally in Mongoose. Despite all the documentation and examples provided in Populate, they only show how to save the objectID of one document in another. Let's say I have a parent document ("category") and multiple child documents ("subcategories"), and I want to reference the parent within the children and vice versa. How can this be achieved?

The only solution that crossed my mind was to add objectID references before saving the documents to the database. Here is the code snippet for that:

Category Schema:

let mongoose = require("mongoose")


let categorySchema = new mongoose.Schema({
    name: String,
    sale_type: String,
    sub_categories: [{type: mongoose.Schema.Types.ObjectId, ref: 
    "SubCategory" }]
})

module.exports = mongoose.model("Category", categorySchema)

Subcategory Schema:

let mongoose = require("mongoose")

let subcategorySchema = new mongoose.Schema({
    name: String,
    sale_type: String,
    category: {type: mongoose.Schema.Types.ObjectId, ref: "Category" }
})

module.exports = mongoose.model("SubCategory", subcategorySchema)

Main file: (This route is intended for creating new "Categories")

app.post("/categories", function(req, res){
    let name = req.body.name
    let sale_type = req.body.sale_type
    let sub_categories = req.body.sub_categories.split(",")
    let category = new Category({
        _id: new mongoose.Types.ObjectId(),
        name: name,
        sale_type: sale_type,
        sub_categories: []
    })
    sub_categories.forEach(function(element){
        let sub_category = new SubCategory({
            _id: new mongoose.Types.ObjectId(),
            name: element,
            sale_type: sale_type,
            category: category._id
        })
        sub_category.save(function(err, subcat){
            if (err){
                console.log(err);
                res.status(500).send("")
            } else {
                category.sub_categories.push(subcat._id)
            }
        })
    })
    category.save(function(err, cat){
        if (err){
            console.log(err)
            res.status(500).send("")
        } else {
            res.status(200).json(cat)
        }
    })
})

Upon hitting the "/categories" route to create a new category, the server response meets my expectations:

{
    "sub_categories": [
        "5c2340bf4641017050567fe8",
        "5c2340bf4641017050567fea"
    ],
    "_id": "5c2340bf4641017050567fe6",
    "name": "cat",
    "sale_type": "retail",
    "__v": 0
}

However, when checking with mongo shell for categories saved in the database, this is what is actually stored:

{ "_id" : ObjectId("5c2340bf4641017050567fe6"), "sub_categories" : [ ], 
"name" : "cat", "sale_type" : "retail", "__v" : 0 }

and the sub_categories array remains empty!!!

Answer №1

Your inquiry involved two questions, and I'd like to address the first one which pertains to reciprocally referencing documents:

It's advisable not to utilize an array for storing references if there is a possibility of an infinite number of subcategories. This could lead to performance issues in the future. For a more efficient solution, consider utilizing the "virtual populate" feature introduced since mongoose 4.5. By creating a virtual field in your category, you can automatically retrieve the array of subcategories as demonstrated below:

// Utilize the `ref` property to enable virtual population
Category.virtual('subcategories', {
  localField: '_id',
  ref: 'Subcategory',
  foreignField: 'category'
});

This method allows for accessing the subcategories without actually saving a new field in the Category collection. When querying the document appropriately, you can seamlessly use this feature without encountering issues related to saving arrays of references:

Category.find().populate('subcategories')

You may find further insights on this matter in the following article:

Additionally, this approach should help alleviate or circumvent your second concern since the field no longer persists in the database. If the data is not displaying as expected, consider verifying the database updates in your code before returning the data. Ensuring that the correct data is written to the database can aid in troubleshooting any discrepancies. For detailed investigation into this issue, consider posing a separate question focused solely on this problem with a simplified sample code.

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

I need to incorporate five pages of input data fields into five separate tables and link them using the primary key in order to design the backend node API effectively

I need to input customer data across 5 pages and store it in 5 separate tables linked by primary keys Should I use a single API for this task or create different APIs for each page? The tables include customer-master, address-table, bank-details-table, a ...

What method can I use to replace the status bar from the top?

Is there a way to smoothly slide in and out a <View/> on React Native iOS, similar to the animation sequences shown in the images below? ...

Issue encountered when sorting sequelize query by date in ascending sequence

My challenge is to arrange a sequelize query in ascending order by date. Specifically, I am focusing on sorting the results of the model: ExamScore (referred to as student_score). I've specified the column "updated_at" for ordering and the method of ...

What is the best way to store changing images in a Next.js application?

Is it possible to set the cache-control for images in a list of objects received from an API? Each object in the list contains a property called imageUrl, which is the link to the image. ...

Angucomplete Alternative solves the challenge of accessing remote URLs

I have been using the Angucomplete Alt directive for creating an autocomplete feature. It has been working well so far, but now I want to customize a specific request to be sent to my server. <div angucomplete-alt id="input-name" ...

Preserve setTimeout() Functionality Across Page Refreshes and Navigations

I am trying to display an alert message after a 15-minute delay, but the functionality is disrupted when the page refreshes or if I navigate to a different page. This all takes place on a single web page. When a specific button is clicked, it should trig ...

retrieve a static method that returns an asynchronous value

Is there a way to have a static ES6 method in my code that simply returns a value instead of a promise? I'm looking for a solution to this problem: export default class Member { static existingMember() { var _existingMember; // DB.findExist ...

Implementing a dual hover effect on a Div element

I am working with HTML code that includes an image and text <div class="subcontainer1"> <img src="a.png" alt="" class="imgcolumn"> <h3 class="header3">Hello</h3> </div> This setup places the content above the image. ...

Is it possible for Angular.js timer finish event not to trigger data binding correctly?

I've been working on an AngularJS application that functions as a quiz by displaying pictures and prompting users to select the correct answer by clicking a button. The app is designed to store the user's answers in an object. Everything seems t ...

Establish a many-to-many relationship in Prisma where one of the fields is sourced from a separate table

I'm currently working with a Prisma schema that includes products, orders, and a many-to-many relationship between them. My goal is to store the product price in the relation table so that I can capture the price of the product at the time of sale, re ...

How can you locate the position of a selector within a parent or set using jQuery

Could someone please help me determine the position of the current selector within its parent using jQuery? I need this information in order to effectively use the .insertAfter() and .insertBefore() methods to rearrange elements within their nested structu ...

How can I utilize Javascript, HTML, JQuery, and CSS to dynamically set a variable based on a HTML Select's OnChange event, perform calculations, and automatically update the result?

I'm in the process of creating a pool pump calculator. While my HTML onchange function is working perfectly, I am struggling with passing the active Div value into my Javascript If Else statement and updating the outputs accordingly for each case of E ...

Challenges in Implementing Shadows with Animations in ThreeJS MeshDepthMaterial

I'm facing an issue where casting shadows through transparent parts of my Mesh using the MeshDepthMaterial causes the shadows of animated objects to stop moving along with the animation. You can see an example of this problem here: https://jsfiddle.n ...

The react-router-dom seems to be malfunctioning, so let's simply render the "/"

Struggling to render multiple pages in React, I am a newbie and have been exploring various tutorials and pages. My stack includes React, Webpack, Babel, and ESLint with Airbnb configuration. When I render my React app, it appears like this. View of the ...

Populating an array in JavaScript with specific values from another array to meet a certain criteria

Looking to implement a function called populateAnimalArray, which takes an array as input and populates it with additional elements based on another argument specifying the required number. const animals = ['lion', 'tiger', 'cheet ...

Guide on displaying API data within nested fields in ReactJS

import axios from 'axios' import { CART_ADD_ITEM } from '../constants/cartConstants' export const addToCart = (uid, qty) => async (dispatch, getState) => { const { data } = await axios.get(`/api/v1/`) dispatch({ ...

Retrieve all records in MongoDB based on a specific field

I am facing challenges when trying to locate all documents based on a specific field value. Essentially, I aim to retrieve all documents by the field companyurl and then extract only the values of the company url fields into a CSV document using csv reader ...

Chrome Extension to Emphasize Every Word

As a novice, I am embarking on the journey of creating my own chrome extension. The idea is to design a popup.html file that showcases a "highlight" button. The functionality would involve clicking this button to highlight all words on the page. Here&apos ...

Looking for assistance in locating documents with unpredictable field names

I searched extensively through the MongoDB documentation and conducted multiple Google searches in an attempt to find a suitable answer, but unfortunately came up empty-handed. I encountered a particular issue where I needed to search for documents within ...

Triggering a keyboard *ENTER* event on an Input in Javascript/React by clicking a button is a common query among developers

I am facing a challenge with an Input element that only displays results when I press Enter on the keyboard. The element is part of a third-party extension, so my control over it is limited. My goal is to trigger the ENTER event for the Input when a button ...