Eladiorocha
Eladiorocha

Reputation: 146

Push items into array of objects with array attribute in mongoose

Hello I am trying to add an element to an array that is inside an object and the object in turn inside an array, below is the structure.

// Schema called "Team" with mongoose
category: [
{
  seasson: { type: String, required: true },
  categories: [{ type: String, required: true }]
}]
// In code looks like:
[
  {
    seasson: "The seasson name 1",
    categories: ["categoryOne", "categoryTwo"]
  }
  {
    seasson: "The seasson name 2",
    categories: ["categoryOne"] // I want to make push in this array the value "categoryTwo"
  },
]
// I´m trying something like following code:
const status = await Team.updateOne(
  {
    _id: mongoose.Types.ObjectId(teamId),
  },
  { $addToSet: { "category.$last.categories": "categoryTwo"} }
)

Whenever an array has to be pushed into the object, it will be in the last position of the main array. Honestly, I've been trying to find a way for a while, but I can't think of anything that works. Thanks in advance.

Upvotes: 1

Views: 1005

Answers (2)

turivishal
turivishal

Reputation: 36134

There is no straight way to update the last element of the array without any identity, you can use update with aggregation pipeline starting from MongoDB 4.2,

  • $map to iterate loop of category array
  • $mergeObjects to merge current category object with updated categories field
  • $last to get the last element value from category.seasson
  • $cond check condition if above last element's value and current object session matches then do update operation otherwise return existing values
  • $setUnion to concat new value of categories, if it is present then it will do replace
let category = "categoryTwo";
const status = await Team.updateOne(
  { _id: mongoose.Types.ObjectId(teamId) },
  [{
    $set: {
      category: {
        $map: {
          input: "$category",
          in: {
            $mergeObjects: [
              "$$this",
              {
                categories: {
                  $cond: [
                    {
                      $eq: [
                        { $last: "$category.seasson" },
                        "$$this.seasson"
                      ]
                    },
                    { $setUnion: ["$$this.categories", [category]] },
                    "$$this.categories"
                  ]
                }
              }
            ]
          }
        }
      }
    }
  }]
)

Playground

Upvotes: 1

Takis
Takis

Reputation: 8705

The bellow query,adds "categoryTwo" in categories,of the last member of array category.I think this is what you want.

If you can next time give the document in the initial form,describe the query you want,and give the document in the final form,in valid JSON so people can help you easier.

You can try the code here Its pipeline update,needs MongoDB >= 4.2

Data in(Collection)

[
  {
    "_id": 1,
    "category": [
      {
        "seasson": "The seasson name 1",
        "categories": [
          "categoryOne",
          "categoryTwo"
        ]
      },
      {
        "seasson": "The seasson name 2",
        "categories": [
          "categoryOne"
        ]
      },
      
    ]
  }
]

Query

db.collection.update({
  "_id": {
    "$eq": 1
  }
},
[
  {
    "$addFields": {
      "category": {
        "$let": {
          "vars": {
            "without_last": {
              "$slice": [
                "$category",
                0,
                {
                  "$subtract": [
                    {
                      "$size": "$category"
                    },
                    1
                  ]
                }
              ]
            },
            "last_member": {
              "$arrayElemAt": [
                {
                  "$slice": [
                    "$category",
                    -1,
                    1
                  ]
                },
                0
              ]
            }
          },
          "in": {
            "$concatArrays": [
              "$$without_last",
              [
                {
                  "$mergeObjects": [
                    "$$last_member",
                    {
                      "categories": {
                        "$concatArrays": [
                          "$$last_member.categories",
                          [
                            "categoryTwo"
                          ]
                        ]
                      }
                    }
                  ]
                }
              ]
            ]
          }
        }
      }
    }
  }
])

Results

[
  {
    "_id": 1,
    "category": [
      {
        "categories": [
          "categoryOne",
          "categoryTwo"
        ],
        "seasson": "The seasson name 1"
      },
      {
        "categories": [
          "categoryOne",
          "categoryTwo"
        ],
        "seasson": "The seasson name 2"
      }
    ]
  }
]

Upvotes: 1

Related Questions