Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When updating elements of primitive array using positional filtered operator, update value is incorrectly cast to array #14595

Closed
2 tasks done
letsgolesco opened this issue May 15, 2024 · 0 comments
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@letsgolesco
Copy link

letsgolesco commented May 15, 2024

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

7.6.2

Node.js version

20.13.1

MongoDB server version

7.0.8

Typescript version (if applicable)

5.2.2

Description

When using the filtered positional operator to update specific element(s) of an array of primitives (e.g. strings), mongoose incorrectly changes the input value from a primitive (e.g. string) to an array containing the input value.

This seems to be due to a misunderstanding of the intent of the operation. Mongoose identifies that the schema type of the path to be updated is an array, and therefore casts the input value to be an array. However, the intent of the update is to modify individual elements of that array, so the schema type for the input value should be identified as the type of the elements of the array, rather than an array itself.

This bug is not present in 7.6.1, but it appears in 7.6.2 and is still present in 7.6.11.

Steps to Reproduce

Here's an example snippet. The additional nesting might not be entirely necessary to reproduce the bug, but it's how I encountered it.

const mongoose = require('mongoose');

const userSchema = {
  groups: [{
    document: mongoose.Schema.Types.ObjectId,
    tags: [String],
  }],
};

const User = mongoose.model('User', userSchema);

const groupId = new mongoose.Types.ObjectId();

await User.create({
  groups: [{
    document: groupId,
    tags: ['tag-first', 'tag-to-update', 'tag-last'],
  }],
});

await User.updateMany(
  { 
    groups: {
      $elemMatch: {
        document: groupId,
        tags: 'tag-to-update',
      },
    },
  },
  {
    $set: {
      'groups.$[group].tags.$[tag]': 'tag-modified',
    },
  },
  {
    arrayFilters: [
      { 'group.document': groupId },
      { tag: { $eq: 'tag-to-update' } },
    ],
  },
);

const userAfter = await User.findOne({});
console.log(userAfter.groups[0].tags);
// ['tag-first', ['tag-modified'], 'tag-last']

Expected Behavior

Since the intent of the update is to modify individual element(s) of the array, rather than the array itself, the schema type of the elements of the array (e.g. in this case, String) should be used for casting.

The output of the example script should be:

// ['tag-first', 'tag-modified', 'tag-last']
@letsgolesco letsgolesco changed the title Positional update operator on element of array is incorrectly cast to array When updating elements of primitive array using positional filtered operator, update value is incorrectly cast to array May 15, 2024
@vkarpov15 vkarpov15 added this to the 7.6.12 milestone May 17, 2024
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label May 17, 2024
@vkarpov15 vkarpov15 added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels May 18, 2024
vkarpov15 added a commit that referenced this issue May 21, 2024
fix(update): cast array of strings underneath doc array with array filters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
Development

No branches or pull requests

2 participants