Searching for values with the same name in nested object

Hi,

I wanted to search in a nested mongo doc for values with a specific name.

The structures of the a little complex but the names of the values are always the same. Here is what one document is looks like:

{
        "nr" : "00000209",
        "tx" : "text",
        "list" : [
                {
                    "featurename" : "text",
                    "featuretext" : "text"
                },
                {
                    "featurename" : "text",
                    "featuretext" : "text",
                    "features" : [
                            {
                                "some" : "text",
                                "featurekeys" : [
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekeys" : ""
                                        }
                                ]
                            }
                    ]
                },
                {
                "featurename" : "text",
                "featuretext" : "text",
                "features" : [
                        {
                                "some" : "text",
                                "featurekeys" : [
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekey" : "text"
                                        },
                                        {
                                                "featurekeys" : "text"
                                        }
                                ]
                        },
                        {
                                "some" : "text",
                                "featurekeys" : [
                                        {
                                                "featurekey" : "text"
                                        }
                                ]
                        }
                ]
            }

        ]
}

Normally I’ve a list of values [‘taxtA’, ‘textB’, ‘textC’] and i have to look through all the featurekey fields if one or more values from my list are there.

My attempt looked like this, but gave me strange results:

{list: {$elemMatch: { features.featurekeys.featurekey:{ $all:[ RegExp('.*TextA.*'), RegExp('.*TextB.*'), RegExp('.*TextC.*')]}}}}

Can anyone tell me what I am doing wrong?

Hi @Herb,

What blocks u from going the full route before doing an $elemMatch on that level:

list.features.featurekeys : { $elemMatch  : {...} }

Please note that $all will require all elements to be in the list vs $any.

Additionally, a wild card regex is a badly performant query and you should consider building a relevant text index and use a text search or Atlas search service.

Best regards
Pavel

1 Like

Thanks a lot for that advise creating a text index, Pavel.

I’ve created a text index for
nr
tx
features.featurekeys.featurekey

this works perfect but i cant use wildcards/regex’s in {$text: {$search: … } anymore wich would be necessary in some cases. For example some data contains “_” between two words some have spaces.
Is there a way to use wildcards in a text index?

Hi @Herb,

Thanks for the feedback. I think that using a text search for the wide range of cases followed by a next stage of match and $regex is expected to work much better than regex from beginning.

Consider exploring the usage of pharses and negation :
https://docs.mongodb.com/manual/reference/operator/query/text/#phrases

Let me know if you have any further questions.

Best regards
Pavel

1 Like

Thanks again Pavel. The phrases are verry helpfull.
Is there a way to combine a $text $search with an another query like {nr:RegExp(“123.+”)} where either one or both are matching?

Hi @Herb,

Well maybe a usage of $facet where one is a text search result and the second one is a regex:

https://docs.mongodb.com/manual/reference/operator/aggregation/facet/

Best regards
Pavel

Aggregation is a hell of a tool, no doubt. but iam not sure if it fits my needs.

Maybe i should explain me problem a little better.
My app gets a textlist to search for. the list not in a predictable order so i have to check if a string matches either “nr”, “txt” or any “featruekey”. I wont only the documents where all values are matching

Hi @Herb,

Ok so my Idea is that you create a text index on the three fields.

Aggregation have several stages.

  1. Search for the needed string/phrase in those fields with a text search.
  2. Second stage of $match will have a $all with an array of regex matches.

This will allow you to first filter all unrelevant objects without this value at all. Following by a strict match on all values.

Let me know if that helps.

Best regards
Pavel

Thanks again. That helped me a lot :slight_smile:

1 Like