0

I am having a problem searching for a key of a nested object.

I have search criteria object that may or may not have certain fields I'd like to search on.

The way I'm solving this is to use conditional statements to append to a "match criteria" object that gets passed to the aggregate $match operator. it works well until I need to match to something inside a nested object.

Here is a sample document structure

{
        name: string,
        dates: {
            actived: Date,
            suspended: Date
        },
        address : [{
            street: string,
            city: string,
            state: string,
            zip: string
        }]

    };

My criteria object is populated thru a UI and passed a JSON that looks similar to this:

{
        "name": "",
        "state": ""
    }

And although I can explicitly use "dates.suspended" without issue - when I try to append address.state to my search match criteria - I get an error.

module.exports.search = function( criteria, callback ) 

        let matchCriteria = {
            "name": criteria.name,
            "dates.suspended": null
        };


        if ( criteria.state !== '' ) {
           // *** PROBLEM HAPPENS HERE *** //
            matchCriteria.address.state = criteria.state;
        }

        User.aggregate([
            { "$match": matchCriteria },
            { "$addFields": {...} },
            { "$project": {...} }
        ], callback );

    }

I get the error:

TypeError: Cannot set property 'state' of undefined

I understand that I'm specifying 'address.state' when 'address' doesn't exist yet - but I am unclear what my syntax would be surely it woulnd't be matchCriteria['address.state'] or "matchCriteria.address.state"

Is there a better way to do conditional filtering?

4
  • In this case matchCriteria.address.state = criteria.state; you are trying to accessing the key address which does not exists and that's why you are getting the error and in the second one matchCriteria['address.state'] you are defining the key address in matchingCriteria object which works perfect. Commented Sep 16, 2018 at 4:45
  • matchCriteria['address.state'] did NOT work for me - same error Commented Sep 16, 2018 at 16:06
  • It works for me. and I explained above why this should work. Commented Sep 16, 2018 at 16:15
  • yes Anthony - I agree it should work, I've used that syntax before in other languages and it works - for the reasons you stated. But it did not work here - and part of the reason I posted, normal things were not working. Commented Sep 16, 2018 at 16:20

3 Answers 3

2

For search in Nested Object, You have to use unwind

A query that help you :

//For testing declare criteria as const

 let  criteria = {name : 'name', 'state' : 'state'};
 let addressMatch = {};
 let matchCriteria = {
            "name": criteria.name,
            "dates.suspended": null
        };


        if ( criteria.state) {

            addressMatch = { 'address.state' :  criteria.state };
        }

db.getCollection('user').aggregate([{
    $match :matchCriteria,
    },{$unwind:'$address'},
    {$match :  addressMatch}
    ])
Sign up to request clarification or add additional context in comments.

Comments

0

Firstly check for address, and then access the property as shown:

if(matchCriteria['address']) {
 matchCriteria['address']['state'] = criteria['state'];
}
else {
//otherwise
}

1 Comment

This is a modification of scthi's response - and also does not work in this instance - although I've used this syntax also in other languages.
0

This should fix it:

matchCriteria['address.state'] = criteria.state;

1 Comment

While this syntax works for me in other languages - it still errors in this instance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.