Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB query IN array of object

I have problem to retrieve information between two collections. The first collection stores employees information:

{
        "_id" : ObjectId("4f9643967f8b9a3f0a00005a"),
        "birth_date" : "1963-09-09",
        "departments" : [
                {
                        "departments_id" : ObjectId("4f9643957f8b9a3f0a000007"),
                        "from_date" : "1990-01-03",
                        "to_date" : "1990-01-15"
                }
        ],
        "first_name" : "Parviz",
        "gender" : "M",
        "hire_date" : "1990-01-03",
        "last_name" : "Lortz",
}

the second one the departments information

{
        "_id" : ObjectId("4f9643957f8b9a3f0a000004"),
        "dept_name" : "Marketing",
        "managers" : [
                {
                        "employees_id" : ObjectId("4f96439b7f8b9a3f0a0186a9"),
                        "from_date" : "1985-01-01",
                        "to_date" : "1991-10-01"
                },
                {
                        "employees_id" : ObjectId("4f96439b7f8b9a3f0a0186aa"),
                        "from_date" : "1991-10-01",
                        "to_date" : "9999-01-01"
                }
        ]
}

I try to find: All departments for a given employee.

I tried something like:

employees = db.employees.find({_id:ObjectId("some_id")});
db.departments.find({_id:{$in:...}});

But I don't know how I can explain $in department_id of all departments from var employees.

like image 965
Kakawait Avatar asked Apr 24 '12 12:04

Kakawait


People also ask

Can you have an array of objects in MongoDB?

In MongoDB's document model, a 1:N relationship data can be stored within a collection; this is a de-normalized form of data. The related data is stored together and can be accessed (and updated) together. The comments are stored as an array; an array of comment objects.

How do I access nested objects in MongoDB?

In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

How do I match an array in MongoDB?

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria. If you specify only a single <query> condition in the $elemMatch expression, and are not using the $not or $ne operators inside of $elemMatch , $elemMatch can be omitted.


2 Answers

There is an easy way to do that in Mongo 3.2, at least in just a single operation:

const employees = db.employees.find(); // query the employees collection
db.departments.find({
  managers: {
    $elemMatch: {
      employees_id: {
        $in: employees.map(e => e._id)
      }
    }
  }
});

The $elemMatch modifier (see ref) helps query against an array-like value of an object property.

like image 133
rishat Avatar answered Oct 14 '22 14:10

rishat


This can not be done with a simple query. You will have to loop over employees.departments and for each iteration add its departments_id to an array. This array you then can use in your second line. This is something best done in your language of choice.

In order to make this easier, you'll have to change your schema. One option is to store the department information in the employee record, but in your case you'd be duplicating a lot of data.

I would instead suggest to have each department contain a list with employee IDs and dates instead like this:

{
        "_id" : ObjectId("4f9643957f8b9a3f0a000004"),
        "dept_name" : "Marketing",
        "managers" : [
        ]
        "employees" : [
            {
                    "employee_id" : ObjectId("4f9643967f8b9a3f0a00005a"),
                    "from_date" : "1990-01-03",
                    "to_date" : "1990-01-15"
            }
        ]
}

In that case, you can then simply run:

db.departments.find( { "employees.employee_id": ObjectId("some_id") } );
like image 45
Derick Avatar answered Oct 14 '22 16:10

Derick