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

removing keys not defined in schema via bulkWrite #8778

Closed
Monokai opened this issue Apr 10, 2020 · 6 comments · Fixed by #8782
Closed

removing keys not defined in schema via bulkWrite #8778

Monokai opened this issue Apr 10, 2020 · 6 comments · Fixed by #8782
Milestone

Comments

@Monokai
Copy link

Monokai commented Apr 10, 2020

I'm using Node 12, MongoDB 3.5.5 and Mongoose 5.9.7.

I'm looking for a way to delete old keys from my documents. As I understand, I need to set strict to false to bypass schema validation, because these keys don't exist in the schema definition anymore. I'm using bulkWrite(updates), and my updates array looks like this:

[{
 "updateOne": {
  "filter": {
   "_id": "5b7d7db6ed9541125a66f762"
  },
  "update": {
   "$unset": {
    "variable1": 1,
    "variable2": 1
   }
  },
  "strict": false
 }
},
{
 "updateOne": {
  "filter": {
   "_id": "5b7da10fd34232134b2ebf06"
  },
  "update": {
   "$unset": {
    "variable3": 1
   }
  },
  "strict": false
 }
}]

The bulk write result looks something like this:

BulkWriteResult {
  result: {
    ok: 1,
    writeErrors: [],
    writeConcernErrors: [],
    insertedIds: [],
    nInserted: 0,
    nUpserted: 0,
    nMatched: 3,
    nModified: 3,
    nRemoved: 0,
    upserted: []
  },
  insertedCount: 0,
  matchedCount: 3,
  modifiedCount: 3,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: {},
  n: 0
}

The old keys are not deleted though, doesn't matter if I use strict or not. I've also tried setting bypassDocumentValidation to true on the bulkWrite() call.

How can I delete old keys that don't exist in the schema definition anymore via bulkWrite?

@AbdelrahmanHafez
Copy link
Collaborator

Welcome @Monokai

You need to set strict: false on your schema:

// 8778
const mongoose = require('mongoose');
const { Schema } = mongoose;
const assert = require('assert');


run().catch(console.error);

async function run () {
  await mongoose.connect('mongodb://localhost:27017/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });

  await mongoose.connection.dropDatabase();

  const userSchema = new Schema({
    name: { type: String }
  }, { strict: false });

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

  await User.create({ name: 'Hafez' });

  await User.bulkWrite([{
    updateOne: {
      filter: { name: 'Hafez' },
      update: { $set: { notInSchema: true } }
    }
  }]);

  // using collection `findOne` to get the document directly from the database
  // without any work from mongoose side
  const user = await User.collection.findOne({ name: 'Hafez' });

  assert.equal(user.notInSchema, true);
  console.log('Done.');
}

@AbdelrahmanHafez AbdelrahmanHafez added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Apr 10, 2020
@Monokai
Copy link
Author

Monokai commented Apr 10, 2020

@AbdelrahmanHafez Thank you for the suggestion. But what if I want to keep my schema strict, but not in a particular update? I understand you can override the strict setting in the update calls right?

@AbdelrahmanHafez
Copy link
Collaborator

Yes, you can do that on Model.updateOne(...) for example, but I couldn't find a strict option in the docs for bulkWrite

Using the native bulkWrite would bypass any mongoose trimming to fields for that specific operation, and you get to keep your schema strict:

// 8778
const mongoose = require('mongoose');
const { Schema } = mongoose;
const assert = require('assert');


run().catch(console.error);

async function run () {
  await mongoose.connect('mongodb://localhost:27017/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });

  await mongoose.connection.dropDatabase();

  const userSchema = new Schema({
    name: { type: String }
  });

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

  await User.create({ name: 'Hafez' });

  // using native bulkWrite to bypass any work done by mongoose
  await User.collection.bulkWrite([{
    updateOne: {
      filter: { name: 'Hafez' },
      update: { $set: { notInSchema: true } }
    }
  }]);

  // using collection `findOne` to get the document directly from the database
  // without any work from mongoose side
  const user = await User.collection.findOne({ name: 'Hafez' });

  assert.equal(user.notInSchema, true);
  console.log('Done.');
}

Does that help?

@Monokai
Copy link
Author

Monokai commented Apr 10, 2020

@AbdelrahmanHafez Thank you. Yes, using the native query it worked flawlessly!

@Monokai Monokai closed this as completed Apr 10, 2020
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Apr 11, 2020
@AbdelrahmanHafez AbdelrahmanHafez added this to the 5.9.9 milestone Apr 11, 2020
@AbdelrahmanHafez AbdelrahmanHafez removed the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Apr 11, 2020
@AbdelrahmanHafez
Copy link
Collaborator

@Monokai

In v5.9.9, you can pass strict: false on bulkWrite options without using the native bulkWrite method. This way you can still use the casting that happens by mongoose.

@aasutossh
Copy link

aasutossh commented Nov 29, 2023

@AbdelrahmanHafez I have mongoose 5.13.7, but the type definition for bulkWrite only has following options (tldr: doesn't have strict)

/**
 * Options for Collection.bulkWrite
 *
 * @see https://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html#bulkWrite
 */
export interface CollectionBulkWriteOptions extends CommonOptions {
    /**
     * Serialize functions on any object.
     */
    serializeFunctions?: boolean | undefined;
    /**
     * Execute write operation in ordered or unordered fashion.
     */
    ordered?: boolean | undefined;
    /**
     * Allow driver to bypass schema validation in MongoDB 3.2 or higher.
     */
    bypassDocumentValidation?: boolean | undefined;
    //Force server to assign _id values instead of driver.
    forceServerObjectId?: boolean | undefined;
}

So I am unable to pass {strict: false} to bulkWrite when using typescript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants