Exploring the differences between arrays and filter functions within MongoDB aggregation operations

Recently, I crafted a sophisticated pipeline for my database:

let orders = await Order.aggregate(
        {
          $unwind: "$candidate",
        },
        {
          $lookup: {
            from: "groups",
            localField: "candidate.groupId",
            foreignField: "_id",
            as: "groupData",
          },
        },
        {
          $lookup: {
            from: "users",
            let: {
              id: "$candidate.groupId",
            },
            pipeline: [
              { $match: { groupId: { $ne: null } } },
              {
                $match: {
                  $expr: { $in: ["$$id", "$groupId"] },
                },
              },
              { $project: { name: 1, email: 1, _id: 1 } },
            ],
            as: "members",
          },
        },
        { $match: { "members._id": new ObjectId(req.userId) } },
        {
          $lookup: {
            from: "users",
            let: { ids: "$candidate.autonomousId" },
            pipeline: [
              {
                $match: {
                  $expr: { $in: ["$_id", "$$ids"] },
                },
              },
              { $project: { name: 1, email: 1, _id: 1 } },
            ],
            as: "candidate",
          },
        },
        {
          $project: {
            groupData: 1,
            members: 1,
            candidate: 1,
            stillAvailable: 1,
            _id: 0,
          },
        }
      ).toArray();

After executing the pipeline, I obtained the expected result...

{ candidate:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' } ],
   groupData:
    [ { _id: 606632403fffb851b8c41d12,
        name: 'Giraia' } ],
   members:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' },
      { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas'} ] } 

However, in order to enhance the organization of my code, I aimed to merge the last step of manually comparing and filtering the members array with the candidates array into the pipeline itself. Despite numerous attempts, I couldn't achieve this using aggregation. As a workaround, I had to process the incomplete pipeline result in my backend. Here is the snippet of code I used:

  orders.forEach(
    (order) =>
      (order.stillAvailable = order.members.filter(
        (autonomous) =>
          !order.candidate.some((el) => {
            return el._id.toString() === autonomous._id.toString();
          })
      ))
  );

This adjustment led me to the desired outcome...

 { candidate:
    [ { _id: 601817dc2eeecd17db3a68f6,
       name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
       name: 'Jose' } ],
   groupData:
    [ { _id: 606632403fffb851b8c41d12,
        name: 'Giraia' ],
   members:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' },
      { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas' ],
   stillAvailable:
    [ { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas' ] }

The challenging part is finding a way to integrate the final step, currently handled by backend logic, directly into the aggregation pipeline. Any suggestions on how to accomplish this task?

Answer №1

Once I posted my question here, I found that my idea became more organized and I was able to achieve the desired outcome by utilizing $map along with an additional level of $lookup! I have decided to keep my answer documented here in case it may help someone facing a similar issue.

  let orders = await Order.aggregate(
    {
      $unwind: "$candidate",
    },
    {
      $lookup: {
        from: "groups",
        localField: "candidate.groupId",
        foreignField: "_id",
        as: "groupData",
      },
    },
    {
      $lookup: {
        from: "users",
        let: {
          id: "$candidate.groupId",
        },
        pipeline: [
          { $match: { groupId: { $ne: null } } },
          {
            $match: {
              $expr: { $in: ["$$id", "$groupId"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "members",
      },
    },
    { $match: { "members._id": new ObjectId(req.userId) } },
    {
      $lookup: {
        from: "users",
        let: { ids: "$candidate.autonomousId" },
        pipeline: [
          {
            $match: {
              $expr: { $in: ["$_id", "$$ids"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "candidate",
      },
    },
    {
      $project: {
        groupData: 1,
        members: 1,
        candidate: 1,
        _id: 0,
        stillAvailable: {
          $setDifference: [
            {
              $map: {
                input: "$members",
                as: "member",
                in: "$$member._id",
              },
            },
            {
              $map: {
                input: "$candidate",
                as: "el",
                in: "$$el._id",
              },
            },
          ],
        },
      },
    },
    {
      $lookup: {
        from: "users",
        let: {
          ids: "$stillAvailable",
        },
        pipeline: [
          {
            $match: {
              $expr: { $in: ["$_id", "$$ids"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "stillAvailable",
      },
    }
  ).toArray();

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

Is it possible to send a request to the backend and continuously scan and update the database until a match is found, and then send the response?

I’m currently facing a challenge in developing my own matchmaking system for a two-player multiplayer game. I have a "play" button that, when pressed by the user, should update their schema property in the database to "inQueue: true". After this update, ...

Automatically populate form fields with data from the clicked row in the HTML table when using JSP

Attempting to populate form fields using jQuery or JavaScript with row elements selected by clicking on the row. Tried a solution from Stack Overflow that didn't work as expected. I'm new to this, so please bear with me. (http://jsbin.com/rotuni/ ...

Error: Unable to retrieve the name property of an undefined object within a React component that is being used as a child component within another parent component

FundraiserScreen.js // Import necessary components and dependencies; // Import Fundraiser component; const Children = ({ loading, error, fundraiserData }) => { if (loading) // Show skeleton loading HTML if (!error) return <Fundraiser fundraiser={fund ...

Looking for assistance in determining a solution for progress bar implementation

Currently, I am developing a simple application using web technologies like HTML, CSS, and jQuery Mobile. This app enables me to create goals and save them to a listview using the <li> element. Every <li> representing a goal will have an assoc ...

Ways to efficiently handle numerous asynchronous requests in a NodeJS/Express API

I am looking to consolidate a variety of REST APIs into a single, easy-to-use API. My plan is to develop a straightforward nodejs/express API that will handle the individual calls asynchronously and then aggregate all the results together at once. The Jav ...

Creating a Redirect Form that Directs Users to a Specific Page Depending on Input Data

Apologies if this is a basic issue, but I'm struggling to figure it out. I am trying to create a form field on a webpage that will redirect users to a specific page based on the data they input. For example, if someone types in "dave" and submits the ...

Verifying conditions in an AJAX-based upload system using JavaScript

Recently, I was working on implementing a JavaScript/AJAX upload system with a progress indicator based on a tutorial. The process went smoothly, and I even managed to include a CSS progress bar for visual representation. However, I encountered a hurdle th ...

Generating a React User-Object in JSON Format

Imagine there is a back-end system using Node.js that allows the creation of users with specific attributes as shown below: POST http://localhost:8080/user Authorization: {{adminToken}} Content-Type: application/json { "userID": "test" ...

Moving objects with Three.JS

Seems like I might just be overlooking a simple solution here. I have a setup with a spotlight pointing backward from the camera towards a plane geometry, as well as some randomly scattered boxes. My goal is to create a basic top-down demo. I move the came ...

Validating the body in Node.js for POST and PUT requests

When working in a production setting, what is considered the standard for POST / PUT body validation? I typically approach it like this: const isValid = (req.body.foo && /[a-z0-9]*/i.test(req.body.foo)) This method involves checking that the var ...

Ways to troubleshoot JavaScript following an AJAX request?

My webpage is structured into three separate files. The index.html file contains a navigation bar, a content box, and a footer within 3 divs. Additionally, there are two other .html files with different content that should load upon clicking specific links ...

The edges of shapes created with ThreeJs appear to have a fuzzy or blurred outline

Trying to create a cube in ThreeJs using Box Geometry, but encountering strange and shaky lines. Even setting wireframe to false doesn't resolve the issue, as the edges remain problematic. https://i.sstatic.net/sUPAX.png Currently utilizing WebGlRen ...

The process of generating a querystring from a form using jQuery is not functioning as expected

I am attempting to send an AJAX request, but I am facing an issue where the query string I am trying to construct turns out to be empty. <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>This project dem ...

React - Defining a global variable within a React component

Can you explain the process to me? I am trying to set up a variable within a react component class so that I can utilize it in multiple sections of my application. Here is what I have attempted: class ColorPick extends React.Component { colorInput; ...

Exploring the best practices for organizing logic within Node.js Express routes

I'm currently utilizing the https://github.com/diegohaz/rest/ boilerplate, but I am unsure about the best practice for implementing logic such as QR code generation and additional validation. My initial thought was to include validation and password ...

Generating a chart using solely the existing data components (values)

I have the following arrays: const elements = ['12345', '12346', '12347', '12348', '12349', '12350']; const fruits = ['Apple', 'Ball']; I want to create a Map using array ele ...

Is there a way to sort search outcomes by a drop-down menu in Next.js?

I am currently working on implementing a filter for my data based on selections made in a drop-down menu. Here's the setup: I have MSSQL data being pulled into NextJS using Prisma (ORM). My goal is to create a dropdown filter that will refine the di ...

Editing the object retrieved from JSON is not possible once it has been fetched

Project. Input text in the field and it appears on the shirt. When you click "see back," there is an issue where new text overlaps old text. Clicking on "see front" allows you to enter new text, with the previous text saved underneath. Question: How can ...

Mocking in AngularJS: Utilizing the same service with varied functions for unit testing with Jasmine

Exploring a new service, Service A, with various functionalities: The snippet of application code is as follows: angular.module('app').factory('ServiceA', function() { var ServiceA = { _retryItem: null, retryItem: ...

SQL AJAX Query Form

I have been searching for tutorials on how to create a good form with PHP and AJAX. I tried starting with a code given to me by a friend and managed to send the request successfully. However, it seems like the data I receive is empty. Could you please take ...