Nick
Nick

Reputation: 5892

Return the first element in a nested array in using mongodb driver for node.js

I'm using the mongodb driver for node.js to query my MongoDB document store.

I have the following data in a document store named companies:

{
  companyName: "My Company",
  users: [
    {
      first: "Nick",
      last: "Kewney",
      email: [email protected],
      username: "this.username",
      company: "Test Company",
    }
  ],
  _id: ObjectId("54a0831fcad79dbf082d65e0")
}

I want to query the store and find any users with the username 'this.username' and return the first.

My attempt below returns the single result but as an array.

db.companies.findOne({ "users.username": "this.username" }, {_id: 0, 'users.$': 1}, next);

Returns...

{
  "users": [
    {
      "first": "Nick",
      "last": "Kewney",
      "email": "[email protected]",
      "username": "this.username",
      "company": "Test Company"
    }
  ]
}

My desired result is only the first item, e.g.

    {
      "first": "Nick",
      "last": "Kewney",
      "email": "[email protected]",
      "username": "this.username",
      "company": "Test Company"
    }

Upvotes: 0

Views: 1382

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151122

There are limitations to what can be done with the basic projection operations available to the .find() method of MongoDB. ,findOne() essentially just wraps .find() to return a single document and not a cursor. But these are basically the same.

If you want first manipulation in the server returned result, you need the .aggregate() method. This has a more detailed $project stage than can do further manipulation, along with other stage operators to get the result:

db.companies.aggregate(
    [
        // Query argument to match document
        { "$match": {
            "users.username": "this.username"
        }},

        // Flatten array out
        { "$unwind": "$users" },

        // Filter array
        { "$match": {
            "users.username": "this.username"
        }},

        // Project wanted fields
        { "$project": {
            "_id": 0,
            "first": "$users.first",
            "last": "$users.last",
            "username": "$users.username",
            "email": "$users.email",
            "company": "$users.company"
        }}
    ],
    function(err,result) {

    }
);

That will give you the result with a restructured document, and also return possible matches for multiple array items as separate results if you needed to.

But for my money, generally just live with what you get from the basic projection. Sure it's nested and also still an array with only 1 item in it, but this is easy to code to manipulate your response. Especially if you truly are using .findOne() in your intended code, as one result is not hard to manipulate there.

Upvotes: 1

Related Questions