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

Problem with blank spaces in collection names #15198

Closed
2 tasks done
yhojann-cl opened this issue Jan 23, 2025 · 3 comments
Closed
2 tasks done

Problem with blank spaces in collection names #15198

yhojann-cl opened this issue Jan 23, 2025 · 3 comments
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary Stale

Comments

@yhojann-cl
Copy link

yhojann-cl commented Jan 23, 2025

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.9.5

Node.js version

22.12.0

MongoDB server version

2.3.4

Typescript version (if applicable)

No response

Description

Due to a coding error I have defined a collection name with a blank space like this:

const mongoose = require('mongoose');

const schema = new mongoose.Schema({
    // Definition ...
});

const model = mongoose.model('foo ', schema);

When using the model to create the database queries I had not noticed this problem, but now that I have seen it I have decided to make the corresponding change to avoid conflicts in data migrations and in the Mongoose middleware.

To detect this problem I have reviewed it from mongoose and from mongosh:

app> db._cachedCollectionNames
[
  'foo '
]

console.log(Object.keys(mongoose.connection.models));
[
  'foo '
]

I understand that mongoose is just a driver that translates between nodejs and mongodb, but I think it's a mistake that it allows creating collections with blank spaces understanding that it's not even capable of maintaining capital letters in the name of the collections, for example, if you want to allow blank spaces to create collections of type 'foo bar' you shouldn't allow a 'foo ' or ' bar'.

My problem arises when I try to solve this problem, I have started by mongosh running:

app> db['foo '].renameCollection('foo')
MongoServerError[NamespaceExists]: target namespace exists

I try force override namespace using the second argument and works fine:

app> db['foo '].renameCollection('foo', true)
{ ok: 1 }

Now that I know it works I have decided to create a migration file so that my code can apply this change automatically in all deployed instances of my application without having to manually run commands on all databases, I have tried to create this:

const mongoose   = require('mongoose');

// Migration
module.exports = async () => {

    // Rename bad collection names
    for(let name of [
        'foo',
        'bar',
    ])
        if(Object.keys(mongoose.connection.models).includes(`${name} `))
            await mongoose.connection.db.collection(`${name} `).rename(name);
}

But does not work, mongoose can not rename the collection, it seems that Mongoose thinks the collection already exists and skips it, does not generate any errors and does not rename it. What can I do?

    console.log(Object.keys(mongoose.connection.models));

    // Rename bad collection names
    for(let name of [
        'foo',
        'bar',
    ])
        if(Object.keys(mongoose.connection.models).includes(`${name} `))
            await mongoose.connection.db.collection(`${name} `).rename(name);

    console.log(Object.keys(mongoose.connection.models));

Says:

[
  'foo '
]
[
  'foo '
]

I can't find much information about the function either: https://mongoosejs.com/docs/api/connection.html#Connection.prototype.db

The mongodb.Db instance, set when the connection is opened

The db property on mongoose is not the same property as mongodb since it is not possible to access the models directly, it is necessary to use .collection and it is not possible to directly access the renameCollection function either, so I think the db property should have its own documentation.

Steps to Reproduce

Create a collection name with a end blank space and try rename without blank space from mongoose.

Expected Behavior

That the name of the collection be modified and the models in mongoose memory be updated with the new changes.

@Imanghvs
Copy link

@yhojann-cl I tested your code and checked everything there. The renaming process works fine. The problem with your code is how you're selecting the collection names array. Test the snippet below (I tested it and it works):

const collectionNames = (await mongoose.connection.db.listCollections().toArray()).map(c => c.name);
for(const name of [
    'foo',
    'bar',
]) {
    if (collectionNames.includes(`${name} `)) {
        await mongoose.connection.db.collection(`${name} `).rename(name);
    }
}

@vkarpov15 vkarpov15 added this to the 8.9.6 milestone Jan 24, 2025
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label Jan 24, 2025
@vkarpov15 vkarpov15 modified the milestones: 8.9.6, 8.9.7 Jan 30, 2025
@vkarpov15
Copy link
Collaborator

The following script works as expected. The collection in MongoDB is renamed, the model name stays the same. Which is expected because rename() just renames the collection.

const mongoose = require('mongoose');


const schema = new mongoose.Schema({
    // Definition ...
});



(async function run() {
    mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test');
    await mongoose.connection.dropDatabase();

    const model = mongoose.model('foo ', schema);
    await model.init();

    console.log('Models', Object.keys(mongoose.connection.models));
    console.log('Collections', await mongoose.connection.listCollections());
      // Rename bad collection names
    for(let name of [
        'foo',
        'bar',
    ])
        if(Object.keys(mongoose.connection.models).includes(`${name} `))
            await mongoose.connection.db.collection(`${name} `).rename(name);

    console.log('Models', Object.keys(mongoose.connection.models));
    console.log('Collections', await mongoose.connection.listCollections());
})();  

Output:

$ node gh-15198.js 
Models [ 'foo ' ]
Collections [
  {
    name: 'foo ',
    type: 'collection',
    options: {},
    info: {
      readOnly: false,
      uuid: new UUID('6fe4682b-1fb0-498a-acaa-8c81dea6fc32')
    },
    idIndex: { v: 2, key: [Object], name: '_id_' }
  }
]
Models [ 'foo ' ]
Collections [
  {
    name: 'foo',
    type: 'collection',
    options: {},
    info: {
      readOnly: false,
      uuid: new UUID('6fe4682b-1fb0-498a-acaa-8c81dea6fc32')
    },
    idIndex: { v: 2, key: [Object], name: '_id_' }
  }
]

A couple potential explanations for the confusion here:

  1. Mongoose does automatically try to create a new collection by default, the above script will fail with MongoServerError: target namespace exists if you remove the dropDatabase() call. You can prevent Mongoose from trying to automatically create a collection when calling mongoose.model() by disabling autoCreate and autoIndex options in your schema or connection options, like mongoose.connect(uri, { autoCreate: false, autoIndex: false }).
  2. Collection.prototype.rename() does not change the Mongoose model name, or the collection that the Mongoose model is tied to. Models are just in-memory structures, so once you have completed renaming your collection you can just do mongoose.model('foo', schema) instead of mongoose.model('foo ', schema) (remove the space). So something like the following
mongoose.deleteModel('foo ');
mongoose.model('foo', schema);

@vkarpov15 vkarpov15 added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Feb 3, 2025
@vkarpov15 vkarpov15 removed this from the 8.9.7 milestone Feb 3, 2025
Copy link

This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary Stale
Projects
None yet
Development

No branches or pull requests

3 participants