Anders Östman
Anders Östman

Reputation: 3832

Refine/Restructure data from Mongodb query

Im using NodeJs, MongoDB Native 2.0+

The following query fetch one client document containing arrays of embedded staff and services.

db.collection('clients').findOne({_id: sessId}, {"services._id": 1, "staff": {$elemMatch: {_id: reqId}}}, callback)

Return a result like this:

{
  _id: "5422c33675d96d581e09e4ca",
  staff:[
    {
      name: "Anders"
      _id: "5458d0aa69d6f72418969428"
      // More fields not relevant to the question...
    }
  ],
  services: [
    {
      _id: "54578da02b1c54e40fc3d7c6"
    },
    {
      _id: "54578da42b1c54e40fc3d7c7"
    },
    {
      _id: "54578da92b1c54e40fc3d7c9"
    }
  ]
}

Note that each embedded object in services actually contains several fields, but _id is the only field returned by means of the projection of the query.

From this returned data I start by "pluck" all id's from services and save them in an array later used for validation. This is by no means a difficult operation... but I'm curious... Is there an easy way to do some kind of aggregation instead of find, to get an array of already plucked objectId's directly from the DB. Something like this:

{
  _id: "5422c33675d96d581e09e4ca",
  staff:[
    {
      name: "Anders"
      _id: "5458d0aa69d6f72418969428"
      // More fields not relevant to the question...
    }
  ],
  services: [
    "54578da02b1c54e40fc3d7c6",
    "54578da42b1c54e40fc3d7c7",
    "54578da92b1c54e40fc3d7c9"
  ]
}

Upvotes: 1

Views: 1502

Answers (1)

BatScream
BatScream

Reputation: 19700

One way of doing it is to first,

$unwind the document based on the staff field, this is done to select the intended staff. This step is required due to the unavailability of the $elemMatch operator in the aggregation framework.

There is an open ticket here: Jira

Once the document with the correct staff is selected, $unwind, based on $services. The $group, together $pushing all the services _id together in an array.

This is then followed by a $project operator, to show the intended fields.

db.clients.aggregate([
{$match:{"_id":sessId}},
{$unwind:"$staff"},
{$match:{"staff._id":reqId}},
{$unwind:"$services"},
{$group:{"_id":"$_id","services_id":{$push:"$services._id"},"staff":{$first:"$staff"}}},
{$project:{"services_id":1,"staff":1}}
])

Upvotes: 2

Related Questions