0

I am attempting to build a query to run from Mongo client that will allow access to the following element of a hash within a hash within a hash.

Here is the structure of the data:

"_id" : ObjectId("BSONID"),
"e1" : "value",
"e2" : "value",
"e3" : "value"),
"updated_at" : ISODate("2015-08-31T21:04:37.669Z"),
"created_at" : ISODate("2015-01-05T07:20:17.833Z"),
"e4" : 62,
"e5" : {
    "sube1" : {
        "26444745" : {
            "subsube1" : "value",
            "subsube2" : "value",
            "subsube3" : "value I am looking for",
            "subsube4" : "value",
            "subsube5" : "value"
        },
        "40937803" : {
            "subsube1" : "value",
            "subsube2" : "value",
            "subsube3" : "value I am looking for",
            "subsube4" : "value",
            "subsube5" : "value"
        },
        "YCPGF5SRTJV2TVVF" : {
            "subsube1" : "value",
            "subsube2" : "value",
            "subsube3" : "value I am looking for",
            "subsube4" : "value",
            "subsube5" : "value"
        }
    }
}

So I have tried dotted notation based on a suggestion for "diving" into an wildcard named hash using db.my_collection.find({"e5.sube1.subsube4": "value I am looking for"}) which keeps coming back with an empty result set. I have also tried the find using a match instead of an exact value using /value I am lo/ and still an empty result set. I know there is at least 1 document which has the "value I am looking for".

Any ideas - note I am restricted to using the Mongo shell client.

Thanks.

Jeff Brown
  • 11
  • 2

2 Answers2

0

You have two issues:

  • You're missing one level.
  • You are checking subsube4 instead of subsube3

Depending on what subdocument of sube1 you want to check, you should do

db.my_collection.find({"e5.sube1.26444745.subsube4": "value I am looking for"})

or

db.my_collection.find({"e5.sube1.40937803.subsube4": "value I am looking for"})

or

db.my_collection.find({"e5.sube1.YCPGF5SRTJV2TVVF.subsube4": "value I am looking for"})

You could use the $or operator if you want to look in any one of the three.

If you don't know the keys of your documents, that's an issue with your schema design: you should use arrays instead of objects. Similar case: How to query a dynamic key - mongodb schema design

EDIT

Since you explain that you have a special request to know the count of "value I am looking for" only one time, we can run a map reduce. You can run those commands in the shell.

Define map function

var iurMapFunction = function() {
    for (var key in this.e5.sube1) {
        if (this.e5.sube1[key].subsube3 == "value I am looking for") {
            var value = {
                count: 1,
                subkey: key
            }
            emit(key, value);
        }
    }
};

Define reduce function

var iurReduceFunction = function(keys, countObjVals) {
    reducedVal = {
        count: 0
    };
    for (var idx = 0; idx < countObjVals.length; idx++) {
        reducedVal.count += countObjVals[idx].count;
    }
    return reducedVal;
};

Run mapreduce command

db.my_collection.mapReduce(iurMapFunction,
    iurReduceFunction, {
        out: {
            replace: "map_reduce_result"
        },
    }
);

Find your counts

db.map_reduce_result.find()

This should give you, for each dynamic key in your object, the number of times it had an embedded field subsube3 with value value I am looking for.

Community
  • 1
  • 1
Mario Trucco
  • 1,933
  • 3
  • 33
  • 45
  • sorry I fat fingered - it should be subsube3 not subsube4. And the level represented by the string of numbers is the problem. I do not know what that value is during the query which is why I was trying to "wildcard" around. Under normal circumstances and normal usage the fact the hash name is a dynamically generated would not matter. In this specific instance a request has been made to identify how many documents contain a specific value in subsube3. – Jeff Brown Sep 01 '15 at 16:46
  • @JeffBrown I'm afraid that, if you can't switch to an array like in the linked post, you're not going to be able to find the query you need. There's no such a thing like wildcard on the key names and I think that's by design.. However, if that's only for once, perhaphs we can think at a map reduce. – Mario Trucco Sep 01 '15 at 18:26
  • @JeffBrown I've edited my answer adding a solution with map reduce – Mario Trucco Sep 01 '15 at 20:03
0

So since this is not capable of being made into a javascript/mongo shell array I will go to plan B which is write some code be it Perl or Ruby and pull the result set into an array of hashes and walk each document/sub-document.

Thanks Mario for the help.

Jeff Brown
  • 11
  • 2