Skip to content

Unexpected $set statement to update field of Map type #15350

Closed
@holem

Description

@holem

Prerequisites

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

Mongoose version

8.13.2

Node.js version

23.11.0

MongoDB server version

8.0.8

Typescript version (if applicable)

No response

Description

The document contains a field of type Map, where the values are arrays of something (e.g., numbers). If you do doc.map.get(key), modify the array (e.g., by adding a new value), and then call set(key), Mongoose generates an incorrect query for MongoDB.
However, if you do the same thing but recreate the array after get(key) (e.g., [...doc.map.get(key)]), then Mongoose generates the correct query for MongoDB.

Steps to Reproduce

"use strict";

import mongoose from "mongoose";

console.log("Mongoose version", mongoose.version);

await mongoose.connect("mongodb://127.0.0.1:27017/mongoose_test");
await mongoose.connection.dropDatabase();
mongoose.set("debug", true);

const DocSchema = new mongoose.Schema({
  map: {
    type: Map,
    of: [{ type: Number }],
    default: new Map(),
  },
});
const Doc = mongoose.model("Doc", DocSchema);

const doc = await Doc.create({});
console.log("just created", doc);

doc.map.set("key", [1, 2]);
await doc.save();
console.log("key set", doc);

const list = doc.map.get("key");
// const list = [...doc.map.get("key")];
list.push(3);
doc.map.set("key", list);
await doc.save();
console.log("key get/push/set", doc);

const userLoaded = await Doc.findById(doc._id.toString());
console.log("from db", userLoaded);

Incorrect case (const list = doc.map.get("key");):

Mongoose version 8.13.2
Mongoose: docs.insertOne({ map: Map(0) {}, _id: ObjectId("67fac37873021776275453b0"), __v: 0 }, {})
just created {
  map: Map(0) {},
  _id: new ObjectId('67fac37873021776275453b0'),
  __v: 0
}
Mongoose: docs.updateOne({ _id: ObjectId("67fac37873021776275453b0"), __v: 0 }, { '$set': { 'map.key': [ 1, 2 ] }, '$inc': { __v: 1 } }, {})
key set {
  map: Map(1) { 'key' => [ 1, 2 ] },
  _id: new ObjectId('67fac37873021776275453b0'),
  __v: 1
}
Mongoose: docs.updateOne({ _id: ObjectId("67fac37873021776275453b0") }, { '$set': { 'map.$*': Map(1) { 'key' => [ 1, 2, 3 ] } }}, {})
key get/push/set {
  map: Map(1) { 'key' => [ 1, 2, 3 ] },
  _id: new ObjectId('67fac37873021776275453b0'),
  __v: 1
}
Mongoose: docs.findOne({ _id: ObjectId("67fac37873021776275453b0") }, {})
from db { _id: new ObjectId('67fac37873021776275453b0'), __v: 1 }

Correct case (const list = [...doc.map.get("key")];):

Mongoose version 8.13.2
Mongoose: docs.insertOne({ map: Map(0) {}, _id: ObjectId("67fac4c4564026e97c390825"), __v: 0 }, {})
just created {
  map: Map(0) {},
  _id: new ObjectId('67fac4c4564026e97c390825'),
  __v: 0
}
Mongoose: docs.updateOne({ _id: ObjectId("67fac4c4564026e97c390825"), __v: 0 }, { '$set': { 'map.key': [ 1, 2 ] }, '$inc': { __v: 1 } }, {})
key set {
  map: Map(1) { 'key' => [ 1, 2 ] },
  _id: new ObjectId('67fac4c4564026e97c390825'),
  __v: 1
}
Mongoose: docs.updateOne({ _id: ObjectId("67fac4c4564026e97c390825"), __v: 1 }, { '$set': { 'map.key': [ 1, 2, 3 ] }, '$inc': { __v: 1 } }, {})
key get/push/set {
  map: Map(1) { 'key' => [ 1, 2, 3 ] },
  _id: new ObjectId('67fac4c4564026e97c390825'),
  __v: 2
}
Mongoose: docs.findOne({ _id: ObjectId("67fac4c4564026e97c390825") }, {})
from db {
  _id: new ObjectId('67fac4c4564026e97c390825'),
  map: Map(1) { 'key' => [ 1, 2, 3 ] },
  __v: 2
}

Difference in 3rd query - docs.updateOne:
incorrect - ... '$set': { 'map.$*': Map(1) { 'key' => [ 1, 2, 3 ] } ...
correct - ... '$set': { 'map.key': [ 1, 2, 3 ] } ...

Expected Behavior

Mongoose should generate correct queries to MongoDB in both cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions