sensedeep / dynamodb-onetable

DynamoDB access and management for one table designs with NodeJS
https://doc.onetable.io/
MIT License
690 stars 109 forks source link

Compound global index not updated if only 1 of 2 properties passed to the update function #508

Closed p610 closed 9 months ago

p610 commented 1 year ago

Describe the bug

Global index not updated if only one of 2 fields that gs is made of if passed to update function.

Maybe there are some params i'm not aware of and can amend this behavior although I still believe it should not be a default.

To Reproduce

import {Table} from 'dynamodb-onetable'

import AWS from 'aws-sdk'
const client = new AWS.DynamoDB.DocumentClient({
    region: 'ap-southeast-2',
})

const Schema = {
    version: '0.0.1',
    client,
    name: 'Schema',
    indexes: {
        primary: { hash: 'pk', sort: 'sk' },
        gs2: { hash: 'gs2pk', sort: 'gs2sk', project: 'all' },
    },
    models: {
        Model: {
            pk: { type: String, value: '${_type}#${id}' },
            sk: { type: String, value: '#' },

            id: { type: String, required: true },

            first: { type: Number, required: true, default: 0 },
            second: { type: Number, required: true, default: 0 },

            gs2pk: { type: String, value: '#First#${first}#Second#${second}' },
            gs2sk: { type: String, value: '${_type}#' },
        },
    },
    params: {
        isoDates: true,
        timestamps: true,
        createdField: 'created',
    },
}

export const table = new Table({
    client,
    name: 'MyTable',
    schema: Schema,
    logger: true,
    timestamps: true,
    partial: true,
})

const Model = table.getModel('Model')

async function main(){

   const print = async () => {
     const data = await Model.get({id:"1" }, {hidden:true})
     console.log('gs2pk', data.gs2pk, 'first', data.first, 'second', data.second) 
   }

   await Model.upsert({id:"1", first:1, second:2}, {partial:false})
   await print()
   await Model.update({id:"1", second:3})
   await print()
   await Model.update({id:"1", first:3, second:4})
   await print()
}

main()

returns

gs2pk #First#1#Second#2 first 1 second 2  # all good
gs2pk #First#1#Second#2 first 1 second 3  # goes out of sync
gs2pk #First#3#Second#4 first 3 second 4  # again all good 

which means that gs2pk is out of sync

Expected behavior

The best would be to update gs2 despite not having first property passed to the update function.

At min. it would be great getting an error otherwise developer is not aware that gs is out of sync.

Environment (please complete the following information):

    "aws-sdk": "^2.1369.0",
    "dynamodb-onetable": "^2.7.1"
mobsense commented 12 months ago

Hi,

Unfortunately, that is the design. If you want to update a GSI, you need to provide all the components of the key so it can be correctly identified. If you don't supply all the components, the original item cannot be updated.