Querying MongoDB using multiple joins

Many inquiries regarding joins and MongoDB exist, though numerous responses are outdated and fail to consider features introduced after Mongo 3.x. The specific question at hand is how one might execute a query on a table with conditions related to linked elements.

Below is an overly simplified example:

const Person =  new mongoose.Schema({
  gender: String
});

const Dog =  new mongoose.Schema({
  breed: String
});

const Team =  new mongoose.Schema({
  trainer: {
        type: mongoose.Schema.ObjectId,
        ref: 'Person'
  },
  members: [{
        type: mongoose.Schema.ObjectId,
        ref: 'Dog'
  }]
})

Assuming this setup is already in use and schema modifications are off the table.

The main concern lies in fetching all teams containing at least one member dog of the "Poodle" breed AND with a trainer of gender "male".

Answer №1

If rephrased, the question would be: How can I merge multiple collections in mongoDB?

Let's assume the collection names correspond to model names like dogs, teams, and people (following the Mongoose convention of pluralization). Below is a method to achieve this:

Dog.aggregate([{
        $match: {
            breed: "Poodle"
        }
    },
    {
        $lookup: {
            from: "teams",
            localField: "_id",
            foreignField: "members",
            as: "team"
        }
    },
    {
        $unwind: "$team"
    },
    {
        $lookup: {
            from: "people",
            localField: "team.trainer",
            foreignField: "_id",
            as: "trainer"
        }
    },

    {
        $unwind: "$trainer"
    },

    {
        $match: {
            "trainer.gender": "male"
        }
    },
    {
        $project: {
            breed: 1,
            trainer: 1,
            team: {
                _id: 1
            }
        }
    }
], function(err, teams) {
   console.log(teams)
});

In this pipeline, we:

  1. Start with Dog and match the breed
  2. Use $lookup to combine with teams and retrieve those with "Poodle" members
  3. The result from step 2 is an array of teams. To separate the array, we employ another $unwind operation
  4. Perform another $lookup to join with people and populate the trainer array
  5. Unwind to separate the trainer array
  6. Filter the set for male trainers
  7. Select the desired fields with $project

The output will resemble:

{
    "_id" : ObjectId("596e5500b5174986059958a8"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958de")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}

{
    "_id" : ObjectId("596e5500b5174986059958b2"),
    "breed" : "Poodle",
    "team" : {
        "_id" : ObjectId("596e564fb5174986059958e6")
    },
    "trainer" : {
        "_id" : ObjectId("596e54bfb51749860599589c"),
        "gender" : "male"
    }
}

This method allows us to search Dog and connect with other collections. The final documents root _id is the dog's, not the team's. The structure can be optimized for better readability, akin to Mongoose's population feature.

Remember, this is distinct from Mongoose's population feature. Here, the database server handles document retrieval efficiently in one operation. For sharded collections, population or a different approach might be more suitable as explained here.

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

Issue with CornerstoneJs React restoreImageIdToolState causing annotations to fail to load automatically post-execution

Once this code is executed, I need the annotations to appear without having to hover over the cornerstoneViewport. const restore = () => { let element; const stack = { currentImageIdIndex: 0, imageIds, }; console.log(dico ...

AJAX request function is only successful on the first attempt

Currently, I am implementing AJAX functionality to verify whether a user-input ID exists in the database. If the ID is found, a check mark is displayed; if not, a cross mark is displayed. The issue arises when I input an ID for the first time, which is pr ...

Unable to submit a fetch request

I've been searching for quite some time without finding any answers to this particular issue. The problem I'm facing is that when I attempt to send an asynchronous request to another web page, I'm not receiving any response. I suspect that t ...

We were caught off guard by the TypeScript error: an unexpected token showed up when we were expecting a constructor,

Trying to implement a function within a class in TypeScript. class Test { function add(x: number, y: number): number { return x + y; } } Encountering an error message stating: TypeScript Unexpected token, A constructor, method, access ...

Complete a form on an external website using either C# or Javascript

I am looking for a solution to automatically fill and submit a form from a specific URL, as I need to trigger this process from my domoticz. Despite attempting different methods like using AJAX or injecting JavaScript, I keep encountering issues with the S ...

The error message indicates that the Dbschema, which is a Mongoose Schema, cannot be called

I am attempting to design a basic registration form using MEAN_Stack with mongoose. Here is my models/dbSchema.js var mongoose = require('mongoose'); var Schema = mongoose.Schema; var User = new mongoose.Schema({ FirstName: String, La ...

Choose a division of an element within an embedded frame

Two different pages on the same website, Home.html and Page2.html. Home.html contains the following code: <html> <iframe id="one" src="page2.html" style="display:none"></iframe> <div id="container"> <h1& ...

Choosing a box will cause a dashed rectangle to appear when the mouse is selected

Whenever I try to select an option in my select box, a dotted rectangle appears. How do I remove this feature? https://i.sstatic.net/BzsL2.png I have noticed that many others are also facing the same issue. I tried updating my CSS with some properties ba ...

Resolving the active tab problem within Angular 2 tab components

Can anyone assist in resolving the active tab problem within an angular 2 application? Check out the Plunker link I am using JSON data to load tabs and their respective information. The JSON format is quite complex, but I have simplified it here for cla ...

Using JavaScript, what is the process for getting the value of a child node within Firebase

var ref = firebase.database().ref("games/" + gameId + "/patterns"); ref.on("child_changed", function(snapshot){ var pattern = snapshot.key; console.log(pattern); }); Currently, the code snippet above only logs the key. But how can I extract the player ...

The like button seems to be malfunctioning and I'm not sure what the issue is

I've added the ability for users to like my posts, but it's not working as intended. Here's the code snippet I used: models.py class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField(blank=Tru ...

JavaScript - the act of exiting functions

Is it necessary to explicitly return from a JavaScript function? Unlike in other languages where not returning can result in a stack overflow error, JavaScript seems to handle this differently. Furthermore, due to its asynchronous nature, determining when ...

Retrieving all data from the collections in Mongoose MongoDB

I am currently utilizing MongoDB in conjunction with Mongoose for my project. My goal is to create a database that holds a complete list of countries, each consisting of a name and a collection of cities. Each city will then have an associated list of host ...

Role Based Routing in React allows for different paths and components

I am currently working on a project involving React and I need to implement different routes for admin and driver roles. I have two separate route objects for each role's claims. I am retrieving the user's role from an API and I want to display t ...

Ways to resolve eslint typedef error when using angular reactive forms with form.value

I am facing an issue with my formGroup and how I initialized it. Whenever I try to retrieve the complete form value using form.value, I encounter an eslint error related to typecasting. userForm = new FormGroup<user>({ name: new FormControl<st ...

Transforming dynamic tables into JSON format

Whenever a user adds a new row to the dynamic table to input customer information, I require the data to be submitted in JSON format upon clicking the submit button. HTML <table class="table table-bordered table-hover" id="driver"> ...

Please tap to dial: Access to navigation is restricted

Trying to add a click-to-call link with the following code: <a href="tel:+4912345678912">Tel: +4912345678912</a> Despite Google developers saying it should work, major mobile browsers are blocking the navigation when clicking on the link. It ...

Unable to change the text with Jquery functionality

I currently have an iframe code that contains the word [UID]. My goal is to replace this word with a different word of my choosing. <iframe class="ofrss" src="https://wall.superrewards.com/super/offers?h=asacgrgerger&uid=[UID]" frameborder="0" widt ...

A guide on tallying entries in mongodb

I am new to working with mongodb. Currently, I have a basic email Schema set up as shown below: const emailSchema = new Schema({ from:{ type: String }, to: { type: String }, subject: { type: String }, content: { type: String ...

How can we enhance Backbone.sync() at the Model level to include additional parameters?

Currently, I am facing a challenge with overriding Backbone's sync() method for a Model. I have the function signature set up and it is triggered correctly, but I am unsure about what needs to be included in the function body in order for it to automa ...