MongoDB: How to find a document by an id inside a nested document
Asked Answered
R

3

14

Given a collection like this:..

[
  {
    "_id" : ObjectId("5546329a470000850084a621"),
    "name": "Joe",
    "surname": "Smith",
    "accounts": [
      {
        "_id" : ObjectId("5546329a470000850084a655"),
        "default": true,
        "status" : "approved",
        "activationTime" : ISODate("2013-05-03T14:37:15.025Z")
      },
      {
        "_id" : ObjectId("5546329a470000850084a688"),
        "default": true,
        "status" : "approved",
        "activationTime" : ISODate("2014-06-03T14:37:15.025Z")
      }
    ]
  },
  {
    "_id" : ObjectId("9546329a470079850084a622"),
    "name": "Jimmy",
    "surname": "Brown",
    "accounts": [
      {
        "_id" : ObjectId("5546329a470790850084a651"),
        "default": true,
        "status" : "suspended",
        "activationTime" : ISODate("2015-02-03T14:37:15.025Z")
      },
      {
        "_id" : ObjectId("5546329a470019850084a611"),
        "default": true,
        "status" : "approved",
        "activationTime" : ISODate("2015-04-03T14:37:15.025Z")
      }
    ]
  },
]

... how do I find a document by accounts.N._id? I've tried this...

db.users.find(
  {},
  {
    "accounts": 0, "accounts": {
      "$elemMatch": { "_id" : ObjectId("5546329a470019850084a611"), "default": true }
    }
  }
)

... but it does't work since I get only the _id of all the documents:

{ "_id" : ObjectId("5546329a470000850084a621") }
{ "_id" : ObjectId("9546329a470079850084a622") }

Am I missing something?

EDIT

The result that I actually need is something like this:

{
  "_id" : ObjectId("9546329a470079850084a622"),
  "name": "Jimmy",
  "surname": "Brown"
}

For instance, I need to find by accounts.N._id but without showing the nested document itself.

Reasonable answered 5/5, 2015 at 5:17 Comment(1)
is there any way to update status of Same object?Ovate
T
32

Use dot notation:

When the field holds an embedded document, a query can either specify an exact match on the embedded document or specify a match by individual fields in the embedded document using the dot notation.

db.coll.find({
   "accounts._id" :ObjectId("5546329a470019850084a611")
})

If you need to output only the part of an array where you have your _id you need to use dollar in projection

The positional $ operator limits the contents of an from the query results to contain only the first element matching the query document.

and your query would look like:

db.coll.find({
   "accounts._id" :ObjectId("5546329a470019850084a611")
}, {
   "accounts.$.": 1
})

P.S. if you need the output like in your modified questions, use this:

db.coll.find({
   "accounts._id" :ObjectId("5546329a470019850084a611")
 }, {
   accounts : 0
 })
Tufa answered 5/5, 2015 at 5:25 Comment(1)
Maybe it helps someone: to cast the id string to ObjectId, one must import const objectID = require("mongodb").ObjectIDSchonfeld
S
7

The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition.

In your case:

db.users.find({'_id': ObjectId('5546329a470000850084a621')}, {accounts: {$elemMatch: {_id: ObjectId('5546329a470000850084a655')}}})

Refer: Mongo Docs

Subirrigate answered 5/5, 2015 at 5:33 Comment(1)
It includes example with description and links to that referred page and glossary. So, that person who asked this question can see other MongoDB terminologies.Subirrigate
B
2

Use $elemMatch in criteria and use $ positional operator in project as below :

db.users.find({
  "accounts": {
    "$elemMatch": {
      "_id": ObjectId("5546329a470019850084a611"),
      "default": true
    }
  }
}, {
  "accounts.$._id": 1 // "accounts.$": 1 also works
}).pretty()
Bulrush answered 5/5, 2015 at 5:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.