1

I am trying to query a single embedded document in an array in MongoDB. I don't know what I am doing wrong. Programmatically, I will query this document and insert new embedded documents into the currently empty trips arrays.

{
    "_id" : ObjectId("564b3300953d9d51429163c3"),
    "agency_key" : "DDOT",
    "routes" : [
        {
            "route_id" : "6165",
            "route_type" : "3",
            "trips" : [ ]
        },
        {
            "route_id" : "6170",
            "route_type" : "3",
            "trips" : [ ]
        },
...

    ]
}

Following queries -I run in mongo shell- return empty:

db.tm_routes.find( { routes :  {$elemMatch: { route_id:6165 } } } ).pretty();

db.tm_routes.find( { routes :  {$elemMatch: { route_id:6165,route_type:3 } } } ).pretty();

db.tm_routes.find({'routes.route_id':6165}).pretty()

also db.tm_routes.find({'routes.route_id':6165}).count() is 0.

The following query returns every document in the array

db.tm_routes.find({'routes.route_id':'6165'}).pretty();

{
    "_id" : ObjectId("564b3300953d9d51429163c3"),
    "agency_key" : "DDOT",
    "routes" : [
        {
            "route_id" : "6165",
            "route_type" : "3",
            "trips" : [ ]
        },
        {
            "route_id" : "6170",
            "route_type" : "3",
            "trips" : [ ]
        },
        ...
        ]}

but db.tm_routes.find({'routes.route_id':'6165'}).count() returns 1.

And finally, here is how I inserted data in the first place -in Node.JS-:

async.waterfall([
...
//RETRIEVE ALL ROUTEIDS FOR EVERY AGENCY
        function(agencyKeys, callback) {
          var routeIds = [];
          var routesArr = [];
          var routes = db.collection('routes'); 
//CALL GETROUTES FUNCTION FOR EVERY AGENCY
          async.map(agencyKeys, getRoutes, function(err, results){
            if (err) throw err;
            else {
              callback(null, results);
            }
          });
//GET ROUTE IDS
          function getRoutes(agencyKey, callback){
            var cursor = routes.find({agency_key:agencyKey});
            cursor.toArray(function(err, docs){
              if(err) throw err;
              for(i in docs){
                routeIds.push(docs[i].route_id);
                var routeObj = {
                  route_id:docs[i].route_id,
                  route_type:docs[i].route_type,
                  trips:[]
                };
                routesArr.push(routeObj);
    /* I TRIED 3 DIFFERENT WAYS TO PUSH DATA
//1->


        collection.update({agency_key:agencyKey}, {$push:{"routes":{
                  'route_id':docs[i].route_id,
                  'route_type':docs[i].route_type,
                  'trips':[]
                }}});
    //2->

collection.update({agency_key:agencyKey}, {$push:{"routes":routeObj}});

    */
                  }
    // 3->
                  collection.update({agency_key:agencyKey}, {$push:{routes:{$each:routesArr}}});
                  callback(null, routeIds);
                });
              };
            },
...

    var collection = newCollection(db, 'tm_routes',[]);
    function newCollection(db, name, options){
      var collection = db.collection(name);
      if (collection){
        collection.drop();
      }
      db.createCollection(name, options);
      return db.collection(name);
    }

Note: I am not using Mongoose and don't want to use if possible.

3
  • 1
    You are querying the route_id field with integers { route_id:6165 } yet your schema has the field type listed as a string, this will of course bring empty results. Is this the intended behaviour or a typo on your part? Commented Nov 17, 2015 at 15:00
  • It is not a typo. It is me trying different things because I am new to mongoDB. Since it returns all elements in the array when I query with {route_id:'6165'} I tried it without the quotations as well Commented Nov 17, 2015 at 15:06
  • On a second thought though... I think nothing is wrong with this code. After looking at the examples here more carefully: docs.mongodb.org/v3.0/tutorial/query-documents/…. It just returns the whole object, that's the default behavior. I'm sorry for the fuss.. Commented Nov 17, 2015 at 15:16

2 Answers 2

6

Melis,

I see what you are asking for, and what you need is help understanding how things are stored in mongodb. Things to understand:

  • A document is the basic unit of data for MongoDB and can be roughly compared to a row in a relational database.
  • A collection can be thought of as a table with a dynamic schema

So documents are stored in collections.Every document has a special _id, that is unique within a collection. What you showed us above in the following format is One document.

{
    "_id" : ObjectId("564b3300953d9d51429163c3"),
    "agency_key" : "DDOT",
    "routes" : [
        {
            "route_id" : "6165",
            "route_type" : "3",
            "trips" : [ ]
        },
        {
            "route_id" : "6170",
            "route_type" : "3",
            "trips" : [ ]
        },
        ...
]}

If you run a query in your tm_routes collection. The find() will return each document in the collection that matches that query. Therefore when you run the query db.tm_routes.find({'routes.route_id':'6165'}).pretty(); it is returning the entire document that matches the query. Therefore this statement is wrong:

The following query returns every document in the array

If you need to find a specific route in that document, and only return that route, depending on your use, because its an array, you may have to use the $-Positional Operator or the aggregation framework.

Sign up to request clarification or add additional context in comments.

1 Comment

I just realized that was the case (not returning everything but returning only the object which includes my query result). I will accept your answer since you took the time to explain and also telling me what I really needed at the first place. Thank you so very much. I love StackOverflow =)
0

For Node and Mongodb users using Mongoose, this is one of the ways to write the query to the above problem:

db.tm_routes.updateOne(
    {
      routes: {
        $elemMatch: {
          route_id: 6165 (or if its in a route path then **6165** could be replaced by **req.params.routeid**
        }
      }
    },
    {
       $push: {
         "routes.$.trips":{
             //the content you want to push into the trips array goes here
          }
       }
    }
)

Comments

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.