Searching for nested arrays of objects in a Mongoose query

Currently, my setup includes node v10, mongodb v4.2, and mongoose v5.9.

I have defined a UsersSchema:

const UsersSchema = new Schema({
    name: {
        type: String,
        required: true,
    },
    email: {
        type: String,
        required: true,
        lowercase: true
    },
 ...

A CompaniesSchema is also in place:

const CompaniesSchema = new Schema({
    name: {
        type: String,
        required: true,
    },
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Users',
        required: true
    },
    branches: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Branches'
    }]
    ...

})

Additionally, there's a BranchesSchema structured as follows:

const BranchesSchema = new Schema({
    name: {
        type: String,
        required: true,
    },
    company: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Companies',
        required: true
    }
    users: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Users',
    }]
})

The challenge I am facing involves querying all the companies owned by a user or the companies they are associated with through a branch. Here's what I attempted:

const id = 'MY_USER_ID'
const queryCompanies = await Companies.find({
  $or: [{ user: id }, { "branches.users": [id] }],
});

The { user: id } part of the query functions correctly. However, I am encountering issues when trying to retrieve companies based on the branches the user is associated with. Is it feasible to accomplish this task?

Answer №1

If you're working with the current schema setup, there are two approaches you can take:

  1. Divide into 2 calls:
const id = 'MY_USER_ID';
let companyIds = await Branches.distinct("company", {users: id});
const queryCompanies = await Companies.find({
    $or: [{ user: id }, { _id: {$in: companyIds} }],
});

  1. Utilize $lookup
const id = 'MY_USER_ID';
const queryCompanies = await Companies.aggregate([
    {
        $lookup: {
            from: "branches",
            let: {companyId: "$_id", userId: id},
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $and: [
                                {
                                    $eq: ["$$companyId", "$company"]
                                },
                                {
                                    $setIsSubset: [["$$userId"], "$users"]
                                }
                            ]
                        }
                    }      
                }
            ],
            as: "branches"
        }
    },
    {
        $match: {
            $or: [
                {
                    user: id
                },
                {
                    "branches.0": {$exists: true}
                }
            ]
        }
    }
]);

From my personal viewpoint, I would recommend going with option 1 since MongoDB isn't particularly fond of lookups, especially in this scenario where it involves the entire collection.

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

MongooseServerSelectionError: encountered ECONNRESET while attempting to read the server selection

Having some trouble connecting my Nodejs application to MongoDB Atlas. Encountered this error: After trying to connect, I got an error in the catch block: MongooseServerSelectionError: read ECONNRESET DB connection error: read ECONNRESET Here is the ...

What steps can I take to identify and manage a browser's inability to play a media file?

I am currently utilizing a JavaScript utility to stream mp3 content. Unfortunately, there are instances where I direct users to a file that cannot be played due to external factors. In such cases, Firebug displays an error message indicating that the file ...

Ensure that the TypeScript build process includes the addition of the .js extension

When importing a file using import * as test from './dir/file', I noticed that the .js extension is missing in the build output. I prefer the output file to be like this: import * as test from './dir/file.js' The issue at hand is that ...

I keep encountering an ENOENT error whenever I try to kick off the project using npm start in Next.js. Can someone help me figure out

Having an issue with Next.js, how can I resolve it? [email protected] start next start ▲ Next.js 14.0.2 Local: http://localhost:3000 [Error: ENOENT: no such file or directory, open 'C:\Users\capas\Desktop\00\React&b ...

When the back button is clicked, what happens in Next.js?

Currently, I am facing an issue with maintaining the scroll position on a page when a user navigates back using the browser's back button. The situation involves a list component displaying products, allowing users to scroll down and view all items. U ...

Encountering a 500 server error while trying to send an email using SendGrid in conjunction

Seeking help on integrating an email capture form into a NextJS site by following this tutorial: Simplified the form to only include the email field. The content of my api/contact.js file is as follows: const mail = require('@sendgrid/mail'); ...

What is the best method for starting a string using the symbol '~'?

Hello everyone! I have a task that requires me to add a special feature. The user needs to enter something in a field, and if it starts with the tilde (~), all subsequent entries should be enclosed in a frame within the same field or displayed in a list ...

Refining information and displaying it alongside the "indelible" data - react

I recently implemented a TextField component from the MUI library, along with a useRef hook to capture user input "live" as they type. The goal is to filter rates based on the characters entered by the user. Currently, I am working with an array of rate ke ...

Issue with Vue.js v-for not displaying component

Hello, I am facing an issue with the v-for feature as it is not rendering at all. You can view the fiddle by clicking on this link https://jsfiddle.net/tadeyemi/k6s4gv85/. I am puzzled as to why it's not working. Can anyone provide some insight? < ...

JavaScript Express is serving up a blank JSON response

Hello there, I have a specific function that is supposed to generate an Object which I want to send back to the browser. However, for some unknown reason, the browser is receiving an empty Object without any content inside: { pName: [ ] } Below you ...

I am attempting to pass an ID to the Controller using a dynamic button, however, I am encountering difficulties in doing so

I need to pass the object's id to the controller when a button is clicked. Right now, it only works for the first item in the list and not for others. How can I fix this issue? $(document).ready(function () { $("#showTweet").click(function () { ...

Customizing the label styles within MUI's Chip component

Incorporating React with MUI's library has been a seamless experience for me. One of the key MUI components I have integrated is the Chip Within this particular Chip, there lies the label attribute, offering the option to showcase a text f ...

Changing the visual appearance of an alert in JavaScript and HTML

My knowledge in JavaScript is limited, but I have a script that retrieves a query from a Python service to a Mongodb database. The query is returned in the following format: [{CHAIN: "STREET ELM, ELMER", CODE: "1234"}, {CHAIN: "STREET LM, LMAO", CODE: ...

Looking for the module or file associated with a function handle

When working with NodeJS, how can one identify the file or module where a given function was declared based on its function handle? For instance: // File 1 import { test } from './file1' function fileFile(fn: Function){ //... facing an issu ...

Counting consecutive sentences starting with "The" using Javascript

As a newcomer, I am attempting to create a code that can split a copied text into sentences and then identify if three or more consecutive sentences begin with the word "The". My goal is for the program to be flexible regardless of the number of sentence ...

Send data to a JavaScript file

Even though this particular question has been asked and answered multiple times, I am still struggling to find a solution to my problem. I am currently working with Masterpages and JavaScript files, and as many people are aware, Masterpages can be quite t ...

Manipulating a value in an array within an object in a document using Mongoose

I am seeking guidance on how to accomplish a certain task. Currently, I am working on a webshop project for school. I am trying to remove a specific category array from the object located inside the "products" section: https://i.sstatic.net/dnCHG.png Be ...

How can I force a Kendo UI Chart to resize in VueJS?

When integrating Kendo UI's Chart component within a Vue application, how can we trigger the chart to refresh or redraw? Although the chart automatically adjusts to changes in width by filling its parent container horizontally, noticeable stretching ...

Results don't align with search parameters

const searchClientes = (event) => { if (event.target.value === '') { getClientes(); return; } else { const searchTerm = event.target.value; const filteredClients = clientes.filter(cliente => { return cliente.nome ...

Find out the version of the database in a meteor application

Depending on the deployment, I sometimes connect to a 3.2 database and other times to a 2.7 database. Every now and then, I come across a feature that is only available in version 3.2 and not in 2.7, so I need to verify the database version. I have attempt ...