Access deeply nested sub-documents in MongoDB at various levels

I have a complex document structure stored in my mongoDB database and I need to extract specific sub-objects from it.

For example:

{
   "organization": "Tech Inc",
   "CEO": "Alice Johnson",
   "departments": [
      {
         "name": "Engineering"
         "head": "Bob Smith"
         "employees": [
            {
               "name": "Sarah"
               "position": "Software Developer"
            },
            // ... many more employees
         ]
      },
      // ... many more departments
   ]
}

MongoDB recently introduced the ability to retrieve 1-level-deep sub-objects using $elemMatch projection:

var projection = { _id: 0, departments: { $elemMatch: { name: "Engineering" } } };
db.organizations.find({"organization": "Tech Inc"}, projection);
// returns { "departments": [ /* array containing only the matching department */ ]  }

However, attempting to fetch a sub-object at a deeper level (e.g., retrieving a specific employee) using the same method results in an error:

var projection = { _id: 0, "departments.employees": { $elemMatch: { name: "Sarah" } } };
db.organizations.find({"organization": "Tech Inc"}, projection);
// "$err": "Cannot use $elemMatch projection on a nested field (currently unsupported).", "code": 16344

Is there a workaround for retrieving arbitrarily deep sub-objects within a MongoDB document?

I am currently using MongoDB version 2.2.1

Answer №1

In a recent query similar to this one, I was able to provide a general answer that may be helpful (refer to Using MongoDB's positional operator $ in a deeply nested document query)

This approach is specifically designed for Mongo 2.6 and above, utilizing the aggregation framework's $redact function.

Below is an example query tailored to retrieve just the student named Bort from a school called Cool School:

db.users.aggregate({

    $match: { schoolName: 'Cool School' }

}, {

    $project: {

        _id: 0,
        'schoolName': 1,
        'rooms.number': 1,
        'rooms.students': 1

    }

}, {

    $redact: {
        $cond: {
            "if": {
                $or: [{
                    $gte: ['$schoolName', '']
                }, {
                    $eq: ['$number', 100]
                }]
            },
            "then": "$$DESCEND",
            "else": {
                $cond: {
                    "if": {
                        $eq: ['$name', 'Bort']
                    },
                    "then": "$$KEEP",
                    "else": "$$PRUNE"
                }
            }
        }
    }

});

The $redact feature allows for sub-queries by selectively matching or pruning sub-documents within the resolved documents.

To gain a deeper understanding of how $redact works, consider reading more about it here. The design pattern outlined here has specific requirements:

  • The redact condition functions at each level of sub-documents, necessitating unique fields at every level (e.g. avoiding duplicate keys like 'number' for both rooms and students)
  • $redact operates on data fields rather than array indices, meaning if you require the position of a nested document for operations such as updates (for instance), it must be included and maintained in your documents
  • Each segment of the $or statement in $redact should align with desired documents at a given level
  • Thus, each segment of the $or statement must include a match to the unique field at that level. For instance, $eq: ['$number', 100] matches the room numbered 100
  • If no explicit query is specified at a level, the unique field still needs to be encompassed. An empty string can serve as a placeholder with $gte: ['$uniqueField': '']
  • The final document level belongs in the second section of the if expression to ensure retention of the entire document

Answer №2

Unfortunately, I currently don't have easy access to mongodb 2.2 for testing purposes. However, have you given this a try?

var projection = { _id: 0, rooms: { $elemMatch: { "students.name": "Bort" } } };
db.schools.find({"schoolName": "Cool School"}, projection);

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

How can we maintain line breaks in Textfields when using React-Admin and Material UI?

Currently, I am working with React-Admin and encountered an issue where my database field contains line breaks (\n). However, when I try to display it on a page using the following code: <TextField source="extra_details" /> The line breaks are ...

Converting JSON data into an array using JavaScript

Stored in a variable named "response", I have the JSON value below: {"rsuccess":true,"errorMessage":" ","ec":null,"responseList":[{"id":2,"description":"user1"},{"id":1,"description”:"user2"}]} var users=response.responseList; var l = users.length; H ...

Tips for creating a blur effect on all options except for the selected 2 out of 4 using jQuery

My goal is to choose 3 options from a list and once 3 options are selected, all other options will be blurred to prevent further selection. Please review the code snippet I have provided below. Link to File <!DOCTYPE html> <html> <head> ...

Can someone explain why I am consistently receiving the value of undefined when accessing the file Object?

Hi there, I'm new to this so I could really use some assistance... I'm currently working on an API where only registered users can upload a card with an image of their asset for rent. In my cards.js file, I have a post request that should respo ...

JustGage error: Unable to locate element with ID 0 in AngularJS

I developed a custom directive for the JustGage plugin, here is how it looks: function justGage() { return { restrict: 'E', replace: true, scope: { universalId: '@', ...

Ways to verify DOM changes in Vue.js using Mocha testing framework

I am having difficulty grasping some fundamental concepts of unit testing in Vue.js using Karma, Mocha, and Chai. Here is the component I am working on: VueExample.vue <template> <div> <p>{{ name }}</p> <in ...

Executing JavaScript POST Requests Based on User Input Changes

Hey there! I'm working on a feature where the input value is populated based on the selection in a dropdown menu. The idea is that when the user picks a code, the corresponding amount will be displayed. However, I want the select box to retain its or ...

The HTML modal window is experiencing loading issues

I am attempting to implement a modal box that appears on click in an HTML document. The HTML code looks like this: <a href="#openModal">Open Modal</a> <div id="openModal" class="modalDialog"> </div> <a href="#openModal">O ...

Can anyone explain the functionality of passport.initialize() in the context of Node.js and Express

I am currently working on implementing the passport module in my application. After reading some manuals, I found this: app.use(passport.initialize()); app.use(passport.session()); Can someone explain what app.use(passport.initialize()) does exactly? I ...

Matching Tables with JavaScript and JSON

After hours of coding, I'm stuck on a simple task and could really use some assistance. The "users" object contains user account information, with the function "get" meant to retrieve matching objects from this array. var users = [ { name ...

What is the best method for updating the name of a specific field in all of my documents using mongojs?

In my collection, all records have a field called "car". I need to update the name of this field with a new one that I receive from a form. The challenge is to change only the field name without altering the values in each record. So far, I haven't at ...

Manipulating and updating intricate data stored in a MongoDB object nested within an array, which is nested within an object, which is then

I have a MongoDB object structured like this: [{ username: "user1", id: "1", Notifications: { history: { Messages: [Object], Collections: [{ Post: "text here", likes: [ ...

The SyntaxError message indicates that there was an unexpected non-whitespace character found after the JSON data when parsing it

I received an Error message: SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data Here is the code snippet: <script> $(document).ready(function () { $('.edit1').on('change', function () { ...

Locating records containing a subset of sub-documents within a specified search term

Imagine having these specific documents stored in your collection: { foo: [ {bar: 1, baz: 2}, {bar: 3, baz: 4} ] } { foo: [ {bar: 5, baz: 6}, {bar: 7, baz: 8} ] } In each document, there is an array called foo, which contains sub-documents. The following ...

Adjust the height of a div element and enable scrolling to fit the

There are numerous inquiries regarding this particular issue. I have exhausted nearly all possible solutions I could find, yet none of them delivered the desired outcome. This is the structure of my page: <div> <header id="status"> / ...

Next.js encountered an issue with the element type, as it expected either a string for built-in components or a class/function for composite components, but received undefined instead

Recently, while working with next js, I encountered an issue when trying to import a rich text editor into my project. Specifically, when attempting to integrate react-draft-wysiwyg, an error message was displayed: Error: Element type is invalid... (full e ...

What is the best way to silence console.log outputs during testing?

There is a utility function that needs to be tested: var util = function(data) { ..... console.log('msg'); .... return true } Here's my test.js file: describe('Testing the util function', function () { it(&ap ...

Tips for retrieving error messages using the Scala/Java MongoDB api

I'm currently using Casbah, a Scala library for MongoDB. I am encountering an issue with one of my insert operations. val builder = MongoDBObject.newBuilder builder += "_id" -> token.uuid builder += "email" -> token.email builder += "creationTi ...

Linking a Checkbox to a Field's Value in AngularJS

I need assistance with checking/unchecking the checkbox depending on the value of the field services.Register.IsTest. If services.Register.IsTest=True, then the checkbox should be checked. Otherwise, it should remain unchecked. Here is the checkbox code: ...

Unusual Behavior of Next.js Layouts

I am puzzled by the unexpected behavior I'm experiencing. When I refresh the page, my navbar momentarily appears and then quickly fades away. Here is the directory structure of my app: . ├── actions.tsx ├── api │ └── test │ ...