Search code examples
mongodbmongoosesubdocument

How to iterate on mongoose subdocument array of objects


Trying to implement conditional statement relying on subdocument array of objects, so i need to iterate over collection of users in database and check inside each user subdocument array of objects with findIndex as for javascript

Users collection

const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
  username: {
    type: String,
    unique: true,
    required: true,
    lowercase: true
  }
  friends: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
    }
  ],
  family: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
    }
  ],
  acquaintances: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
    }
  ],
  following: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
    }
  ],
  pendingFriendConfirmationData:[
    {
      storedUserId : {type: String},
      choosenCategories: [{label: {type: String}, value: {type: String}}]
    }
  ]
});

const Users = mongoose.model("Users", userSchema);
module.exports = Users;

now i can access Users collection with

db.Users.find()

my example result for

let filter = {"_id": userId}
let projection = {username: 1, friends: 1, family: 1, acquaintances: 1, following: 1, pendingFriendConfirmationData: 1}

db.Users.findOne(filter, projection, (err, user)=>{
      console.log(user)
    })

{
   friends: [],
   family: [],
   acquaintances: [],
   following: [],
   _id: 5ca1a43ac5298f8139b1528c,
   username: 'ahmedyounes',
   pendingFriendConfirmationData: [
     {
       choosenCategories: [Array],
       _id: 5ccb0fcf81a7944faf819883,
       storedUserId: '5cc95d674384e302c9b446e8'
     }
   ]
 }

focusing on pendingFriendConfirmationData the following screenshot from MongoDB Compass

enter image description here

I want to iterate over like this

let filter = {"_id": userId}
let projection = {username: 1, friends: 1, family: 1, acquaintances: 1, following: 1, pendingFriendConfirmationData: 1}

db.Users.findOne(filter, projection, (err, user)=>{
      let data = user.pendingFriendConfirmationData
      for(let i in data){
       if(data[i].choosenCategories.findIndex(v => v.label === "friend") !== -1){
        console.log("he is a friend")
      }
      }
    })

How to iterate over pendingFriendConfirmationData and choosenCategories like above

for now if i console.log(data) as following

db.Users.findOne(filter, projection, (err, user)=>{
      let data = user.pendingFriendConfirmationData
      console.log(data)
    })

I get

enter image description here


Solution

  • I figured it out Faster Mongoose Queries With Lean

    The lean option tells Mongoose to skip hydrating the result documents. This makes queries faster and less memory intensive, but the result documents are plain JavaScript objects (POJOs), not Mongoose documents. In this tutorial, you'll learn more about the tradeoffs of using lean().

    In my previous example the solution would be adding {lean: true}

    db.Users.findOne(filter, projection, {lean: true}, (err, user)=>{
          let data = user.pendingFriendConfirmationData
          console.log(data)
        })
    

    also here

    db.Users.findOne(filter, projection, {lean: true}, (err, user)=>{
          let data = user.pendingFriendConfirmationData
          for(let i in data){
           if(data[i].choosenCategories.findIndex(v => v.value === "friends") !== -1){
            console.log("he is a friend")
          }
          }
        })
    
    // he is a friend
    

    Conclusion

    to iterate over deeply nested subdocument array of objects you need to make sure that you are working with plain JavaScript objects (POJOs) using lean()

    db.Users.find().lean()