Node mongoose embedded document array

Viewed 50

I have my sample userSchema here:

{
    "_id": objectId("6092076ba811e50b565497ec"),
    "username": "test@gmail.com",
    "address_book": [{
        "_id": objectId("6092b1120f7e370b954a2708"),
        "address": "address1",
        "address2": "address2",
    }, {
        "_id": objectId("6093edcb88796b0a5eba19a3"),
        "address": "test1",
       "address2": "test2",
    }]
}

Can I find user by objectId("6092076ba811e50b565497ec") and address_book._id object("6093edcb88796b0a5eba19a3")

and it return only the address_book that I selected? my expected return data should look like this

{
    "_id": objectId("6092076ba811e50b565497ec"),
    "username": "test@gmail.com",
    "address_book": {
        "_id": objectId("6093edcb88796b0a5eba19a3"),
        "address": "test1",
       "address2": "test2",
    }
}

here is my sample function

let user = [];
await User.findOne({
   _id: id,
   "address_book._id": address_id,
 })
.then((result) => {
   console.log(result);
   user = result;
 })
 .catch((err) => console.log(err));
 return user;

with this I get all address_book

and also can is there and updateOrCreate function by address_book._id?

Thank you in advance.

2 Answers

elemMatch is what you are looking for according to me. elemMatch for projection not just the match.

    db.<collection name>.find({
  < search using elem match >
}, {
  games: {
    $elemMatch: {
      //put your projection piece here, whatever selective what you want, check the example on documentation
      score: {
        $gt: 5
      }
    }
  },
  //anything else that you would want apart from within array projection
})

Update :

Data

    [
  {
    "_id": "6092076ba811e50b565497ec",
    "username": "test@gmail.com",
    "address_book": [
      {
        "_id": "6092b1120f7e370b954a2708",
        "address": "address1",
        "address2": "address2",
        
      },
      {
        "_id": "6093edcb88796b0a5eba19a3",
        "address": "test1",
        "address2": "test2",
        
      }
    ]
  }
]

Command

db.collection.find({},
{
  address_book: {
    $elemMatch: {
      address: "test1"
    }
  }
})

Result

[
  {
    "_id": "6092076ba811e50b565497ec",
    "address_book": [
      {
        "_id": "6093edcb88796b0a5eba19a3",
        "address": "test1",
        "address2": "test2"
      }
    ]
  }
]

Playground

You can use aggregation operators in find method starting from MongoDB 4.4,

  • $filter to iterate loop of address_book array and match _id condition
  • $first to select first element from above filtered result
await User.findOne({
  _id: id,
  "address_book._id": address_id
},
{
  username: 1,
  address_book: {
    $first: {
      $filter: {
        input: "$address_book",
        cond: { $eq: ["$$this._id", mongoose.Types.ObjectId(address_id)] }
      }
    }
  }
})

Playground

Related