Updated 2nd level nested subdocument by the id of the nested subdocument

Hello Devs!
I’m new in mongo and i can’t understand how tu update a 2nd level nested document.
We have:

  • a user schema
  • an owner schema that is a polymorphic on user with a discriminator key
  • on owner model we have 1 sub document array places and inside places we have a sub document array cards

We are trying to update a card document providinig a card id in this way
for (const [key, value] of Object.entries(attributes)) {
partialAttributes[places.$[place].cards.$[card].${key}] = value;
}

return this.userService.findOneAndUpdate(
  { 'places.cards._id': id, type: Role.OWNER },
  { $set: partialAttributes },
  {
    new: true,
    arrayFilters: [{ 'place.cards._id': id }, { 'card._id': id }],
  },
);

but we receive this error that is not that undertandable for us:
Could not find path “places.0.cards._id” in schema

Thanks for the help

MM

It would be easier to understand and experiment if you could provide sample documents.

1 Like

@steevej thanks for the reply, sure, this is the document:

{
  "_id": { "$oid": "664da01a9dfd3b3b887dba6a" },
  "name": "Doe",
  "email": "owner@test.it",
  "password": "$2b$10$BpODomLlVeq2.R1.dAfjU.g5WeZaKfsaeTcpkVXzTh/W1xZEUjxMW",
  "role": "OWNER",
  "type": "OWNER",
  "provider": "EMAIL",
  "places": [
    {
      "name": "Xjndfwjkfn",
      "type": "lkjdfs",
      "data": "{}",
      "_id": {
        "$oid": "66462138a825a4da9a2c6b4d"
      },
      "cards": [
        {
          "name": "Card #102",
          "description": "Pkjndfksj",
          "quantity": { "$numberInt": "25" },
          "price": { "$numberInt": "1499" },
          "_id": {
            "$oid": "66462791581f72d1b0684258"
          }
        }
      ]
    }
  ],
  "createdAt": {
    "$date": { "$numberLong": "1715865921701" }
  },
  "updatedAt": {
    "$date": { "$numberLong": "1716296324209" }
  },
  "__v": { "$numberInt": "0" },
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NjQ2MDk0MTZiZDQxZjQ2ZGU3MDZlZWQiLCJuYW1lIjoiRG9lIiwiZW1haWwiOiJvd25lckB0ZXN0Lml0Iiwicm9sZSI6Ik9XTkVSIiwiaWF0IjoxNzE2Mjk2MzI0LCJleHAiOjE3MTY5MDExMjR9._RrRmiDJo3bCeToCkglNRbsRukvMPHyhPLaGbYimg1k"
}

we would like to update the a card info with the code i posted above.

This is the user schema

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
import { Role } from 'src/acl/enums/role.enum';
import { Provider } from 'src/auth/enums/provider.enum';
import { Place } from '../../places/schemas/places.schema';

@Schema({ timestamps: true, discriminatorKey: 'type' })
export class User {
  @Prop()
  name: string;

  @Prop({ required: true, unique: true })
  email: string;

  @Prop()
  emailVerifiedAt: Date;

  @Prop({ required: true })
  password: string;

  @Prop({ default: 'CLIENT', enum: Role })
  role: Role;

  @Prop({ required: true, enum: [Role.OWNER, Role.CLIENT] })
  type: string;

  @Prop({ default: 'EMAIL', enum: Provider })
  provider: Provider;

  @Prop()
  refreshToken: string;
}

export type UserDocument = HydratedDocument<User>;

export const UserSchema = SchemaFactory.createForClass(User);

And this the polymorphic document owner schema

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import {
  Subscription,
  SubscriptionSchema,
} from '../../subscriptions/schemas/subscription.schema';
import { Place } from '../../places/schemas/places.schema';
import { HydratedDocument } from 'mongoose';

@Schema({ timestamps: true })
export class Owner {
  type: string;

  @Prop({ type: SubscriptionSchema })
  subscription?: Subscription;

  @Prop({ type: [Place], default: [] })
  places: Place[];
}

export type OwnerDocument = HydratedDocument<Owner>;

export const OwnerSchema = SchemaFactory.createForClass(Owner);

Can you confirm that you have back ticks before places and after ${key} in

On this side of the post, we do not see them but they are required so that ${key} is expanded correctly?

If I use partialAttributes equals to

{ 'places.$[place].cards.$[card].email': 'steevej' }

You code works just fine with the plain node.js driver. It was not clear from the OP that you were using mongoose but I think that is it in your way in this case.

I am not using mongoose so I cannot help further. I have tagged your post with mongoose so that others who know more about moogoose jumps in.