Search code examples
javascriptmongodbmongooseschemafindoneandupdate

Mongoose FindOneAndUpdate: change value without overwriting current values


I have this schema

{
        guildId: {
            type: String,
            required: true,
            unique: true
        },
        systems:{
            reactChat:{
                type: Array,
                required: true,
                default: []
            },
            notification:{
                tiktok:{
                    user:{
                        type: String
                    },
                    endCooldown: {
                        type: String,
                        default: '0'
                    }
                }
            }
        }

so I want to change the endCooldown value which is in systems > notifications > tiktok using findOneAndUpdate. But when I try to do that, it resets all values, like user. Here's the code I'm using:

GuildSchema.findOneAndUpdate({guildId: id}, {
    systems:{
        notification:{
            tiktok:{
                endCooldown: String(Date.now() + 86400000) //24h
            }
            
        }
        
    }
}, () => {})

How can I make it only change the endCooldown?


Solution

  • When profiling your original update you are effectively submitting the following operation...

    {
    op: 'command',
    ns: 'nodetest.Things',
    command: {
      findAndModify: 'Things',
      query: { guildId: 'GOPd3ccG1f' },
      remove: false,
      new: false,
      upsert: false,
      fields: {},
      update: {
        '$set': { systems: { notification: { tiktok: [Object] } } }
      },
      lsid: { id: UUID("f4462722-1970-43c5-b2e1-b1cc5e38e9d0") },
      txnNumber: Long("2"),
      '$clusterTime': {
        clusterTime: Timestamp(2, 1630100100),
        signature: {
          hash: Binary(Buffer.from("005ff0e9abe7f7386825f291dfdf769ae050f08a", "hex"), 0),
          keyId: Long("6967052092213035012")
        }
      },
      '$db': 'nodetest'
    },
    keysExamined: 1,
    docsExamined: 1,
    nMatched: 1,
    nModified: 1,
    nUpserted: 0,
    numYield: 0,
    queryHash: '6D0EBC2A',
    planCacheKey: '479D3C98',
    locks: {
      ParallelBatchWriterMode: { acquireCount: { r: Long("2") } },
      ReplicationStateTransition: { acquireCount: { w: Long("3") } },
      Global: { acquireCount: { w: Long("2") } },
      Database: { acquireCount: { w: Long("2") } },
      Collection: { acquireCount: { w: Long("2") } },
      Mutex: { acquireCount: { r: Long("2") } }
    },
    flowControl: { acquireCount: Long("1"), timeAcquiringMicros: Long("1") },
    readConcern: { level: 'local', provenance: 'implicitDefault' },
    writeConcern: { w: 'majority', wtimeout: 0, provenance: 'implicitDefault' },
    responseLength: 409,
    protocol: 'op_msg',
    millis: 57,
    planSummary: 'IXSCAN { guildId: 1 }',
    execStats: {
      stage: 'UPDATE',
      nReturned: 1,
      executionTimeMillisEstimate: 0,
      works: 1,
      advanced: 1,
      needTime: 0,
      needYield: 0,
      saveState: 0,
      restoreState: 0,
      isEOF: 1,
      nMatched: 1,
      nWouldModify: 1,
      nWouldUpsert: 0,
      inputStage: {
        stage: 'FETCH',
        nReturned: 1,
        executionTimeMillisEstimate: 0,
        works: 1,
        advanced: 1,
        needTime: 0,
        needYield: 0,
        saveState: 1,
        restoreState: 1,
        isEOF: 0,
        docsExamined: 1,
        alreadyHasObj: 0,
        inputStage: {
          stage: 'IXSCAN',
          nReturned: 1,
          executionTimeMillisEstimate: 0,
          works: 1,
          advanced: 1,
          needTime: 0,
          needYield: 0,
          saveState: 1,
          restoreState: 1,
          isEOF: 0,
          keyPattern: { guildId: 1 },
          indexName: 'guildId_1',
          isMultiKey: false,
          multiKeyPaths: { guildId: [] },
          isUnique: true,
          isSparse: false,
          isPartial: false,
          indexVersion: 2,
          direction: 'forward',
          indexBounds: { guildId: [ '["GOPd3ccG1f", "GOPd3ccG1f"]' ] },
          keysExamined: 1,
          seeks: 1,
          dupsTested: 0,
          dupsDropped: 0
        }
      }
    },
    ts: ISODate("2021-08-27T21:35:00.994Z"),
    client: '127.0.0.1',
    allUsers: [ { user: 'barry', db: 'admin' } ],
    user: 'barry@admin'
    }
    

    This method is setting the systems.notification.tiktok object to a new object, not just the field endCooldown. If you want to only edit the one field endCooldown then provide a targeted update instead...

    GuildSchema.findOneAndUpdate({guildId: id}, { "$set": { "systems.notification.tiktok.endCooldown": String(Date.now() + 86400000)}}, () => {});