Filtering aggregation after invoking $lookup

Is there a way to add a filter after performing an $lookup, or is there another method to achieve this?

The data collection test looks like this:

{ "_id" : ObjectId("570557d4094a4514fc1291d6"), "id" : 100, "value" : "0", "contain" : [ ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d7"), "id" : 110, "value" : "1", "contain" : [ 100 ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d8"), "id" : 120, "value" : "1", "contain" : [ 100 ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d9"), "id" : 121, "value" : "2", "contain" : [ 100, 120 ] }

To select id 100 and aggregate the children:

db.test.aggregate([ {
  $match : {
    id: 100
  }
}, {
  $lookup : {
    from : "test",
    localField : "id",
    foreignField : "contain",
    as : "childs"
  }
}]);

After executing the query, we get:

{  
  "_id":ObjectId("570557d4094a4514fc1291d6"),
  "id":100,
  "value":"0",
  "contain":[ ],
  "childs":[ {  
      "_id":ObjectId("570557d4094a4514fc1291d7"),
      "id":110,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d8"),
      "id":120,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d9"),
      "id":121,
      "value":"2",
      "contain":[ 100, 120 ]
    }
  ]
}

However, if we only want children that have a matching value of "1," the expected result should be:

{  
  "_id":ObjectId("570557d4094a4514fc1291d6"),
  "id":100,
  "value":"0",
  "contain":[ ],
  "childs":[ {  
      "_id":ObjectId("570557d4094a4514fc1291d7"),
      "id":110,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d8"),
      "id":120,
      "value":"1",
      "contain":[ 100 ]
    }
  ]
}

Answer №1

Discussing a topic unrelated to the use of $lookup, this answer provides techniques for filtering after utilizing $lookup. Two methods are presented:

MongoDB 3.6 - Sub-pipeline

db.test.aggregate([
    { "$match": { "id": 100 } },
    { "$lookup": {
      "from": "test",
      "let": { "id": "$id" },
      "pipeline": [
        { "$match": {
          "value": "1",
          "$expr": { "$in": [ "$$id", "$contain" ] }
        }}
      ],
      "as": "childs"
    }}
])

Earlier - $lookup + $unwind + $match coalescence

db.test.aggregate([
    { "$match": { "id": 100 } },
    { "$lookup": {
        "from": "test",
        "localField": "id",
        "foreignField": "contain",
        "as": "childs"
    }},
    { "$unwind": "$childs" },
    { "$match": { "childs.value": "1" } },
    { "$group": {
        "_id": "$_id",
        "id": { "$first": "$id" },
        "value": { "$first": "$value" },
        "contain": { "$first": "$contain" },
        "childs": { "$push": "$childs" }
     }}
])

If you question why would you $unwind as opposed to using $filter on the array, then read Aggregate $lookup Total size of documents in matching pipeline exceeds maximum document size for all the detail on why this is generally necessary and far more optimal.

For releases of MongoDB 3.6 and onwards, then the more expressive "sub-pipeline" is generally what you want to "filter" the results of the foreign collection before anything gets returned into the array at all.

The underlying theme here is that effective data manipulation practices can be achieved without needing complex aggregation operations such as joins or sub-queries, showcasing the efficiency of retrieving related items directly instead.


Original

This response emphasizes that using $lookup may not be the most efficient approach for achieving desired outcomes. It suggests simpler alternatives like $filter or $redact for filtering results post $lookup.

The examples provided illustrate different ways of achieving the same outcome, underscoring the importance of optimizing query performance based on specific requirements.

A key takeaway is the flexibility offered by MongoDB in tailoring queries to efficiently retrieve desired data without relying heavily on advanced aggregation features.

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 there a way to adjust the position of a Bootstrap 5 dropdown menu in real-time using javascript or jQuery?

Within my web app, I have implemented dynamically generated Bootstrap 5 dropdown menus that can sometimes be extensive. To optimize screen space usage, I am seeking a way to alter the offset computed by Popper.js through javascript. Unfortunately, I have e ...

Navigating in a Curved Path using Webkit Transition

Currently, I am working on a simple project to learn and then incorporate it into a larger project. I have a basic box that I want to move from one position to another using CSS webkit animations and the translate function for iOS hardware acceleration. I ...

Troubleshooting problems with displaying views due to asynchronous $http.get calls in AngularJS

Within my application, I am utilizing two separate API calls. The initial call retrieves a catalog of services along with their unique ID's. Subsequently, once the ID information is acquired, a second call is made to retrieve pricing data for each cor ...

How to keep your vue-router up-to-date

As a newcomer to vuejs, I am using vue cli 3 for my project which consists of various components. One of the components is a menu component where I retrieve all the menu items from an API (code provided below). I have integrated vue-router for routing purp ...

In order to access the localStorage from a different component, a page refresh is required as it is

UPDATE: Just to clarify, this question is NOT duplicate of how to retrieve the value from localstorage. My scenario is unique and the issue lies with Angular itself rather than localStorage. I am currently developing an Angular7 application. In one of my ...

ReactJs - Reactstrap | Issue with Jumbotron displaying background color

I am trying to create a gray background using Jumbotron in reactstrap. After installation and reference in required places - index.js import 'bootstrap/dist/css/bootstrap.css'; Jumbotron has been implemented in SignIn.js - import Re ...

Using Selenium in conjunction with browsermob-proxy to generate new HAR files for redirected web pages

Another interesting scenario I have encountered involves combining Selenium with browsermob-proxy: A new Har is created for the initial page access The initial request can be redirected multiple times And then further redirected by JavaScript For exampl ...

Pair each element with an array of objects and add them to a fresh array

Let's consider an array of objects like, const attachmentData = [{name: 'Suman Baidh',attachment: ["123","456"]}, {name: 'John Sigma',attachment: ["789","101112]}, ...

Fetch data dynamically with jQuery AJAX

I am working on a jQuery Ajax form submission to a PHP page with the goal of dynamically returning values instead of all at once. For instance, in my jQuery code: jQuery.ajax({ type: "POST", url: "$PathToActions/Accounts.php", dataType: ...

Creative ways to use images as borders with CSS in React JS

import React, { Component } from 'react'; class BigText extends Component { constructor(props) { super(props); this.state = { title: '', text: '', summary: '' ...

The performance of Ionic scroll is hindered by a slow response time coupled with a

I'm experiencing an issue where the page loads square by square when I scroll, which looks like this: https://i.sstatic.net/yHNLx.jpg Here is the code snippet: categoryList.html <ion-header-bar align-title="center" class="bar-stable"> < ...

Unable to input characters consecutively into the text field because it is being displayed as a distinct function within the component

When attempting to bind a text field using the approach below, I encounter an issue where entering characters in the text field causes the control/focus to shift out of the field after the first character is entered. I then have to click back into the text ...

An array containing concatenated values should be transferred to the children of the corresponding value

Consider this example with an array: "items": [ { "value": "10", "label": "LIMEIRA", "children": [] }, { "value": "10-3", "label": "RECEBIMENTO", ...

What steps can I take to ensure that Mongo 3.0 / WiredTiger loads my entire database into memory?

My database is a static 5 GB file that will never be written to, and my server has a capacity of 30 GB. I am focused on delivering complex aggregations to users as quickly as possible. To achieve this, I believe it would be beneficial to have both the inde ...

To access a restricted selection of images stored in Firebase

Is there a way to load additional images from Firebase by clicking a button? I created a function that looks like this: onLoadMore() { if (this.all.length > 1 ) { const lastLoadedPost = _.last(this.all); const lastLoadedPostKey = lastLoadedP ...

Guide to adding and showing records without the need to refresh the webpage using CodeIgniter

Hey there! I've got a code snippet here for inserting and displaying records without refreshing the web page using AJAX and plain PHP. However, I'm not sure how to set this up using CodeIgniter. Can someone please lend a hand? Here's what I ...

Checkbox fails to display as checked

I am currently working on implementing checkbox inputs in React JS. I have encountered an issue where the checkboxes do not visually show as checked when clicked, but I am still able to retrieve the value of the checkbox. Here is my code: Simple Checkbox I ...

Unable to make changes while state transition is in progress

I want to update the state value based on the result of a promise method. To have optimistic updates, I set the state value before an asynchronous operation. If the operation fails, the state is reset. componentWillMount(){ this.setState({notify: this ...

Adding a local image to Firebase Storage in Angular5 / Ionic3

Uploading images is a breeze using the following method (select input file): import { AngularFireStorage } from 'angularfire2/storage'; @Component({ selector: 'app-root', template: '<div>' + '<input c ...

I'm having trouble grasping the sequence of events in this async example

Currently, I'm delving into the world of JavaScript and Node.js, but I find myself facing challenges with asynchronous execution. I have a piece of code that may not be following best practices, but I am eager to understand why the file remains open w ...