benhutchins / dyngoose

Elegant DynamoDB object modeling for Typescript.
https://www.npmjs.com/package/dyngoose
ISC License
88 stars 14 forks source link

Help - increment value without loading record #675

Closed ktwbc closed 7 months ago

ktwbc commented 10 months ago

Can I ask for an example of using Update together with increment, maybe something could be added to docs.

I can see in the Home read me about loading a record first, then using

card.set('number', 2, { operator: 'increment' })

to increment, but I'm trying to combine increment with the primaryKey.update command to increment a value without preloading the record.

benhutchins commented 10 months ago

To create a record from a primary key without loading it, you can do:

const card = Card.primaryKey.fromKey({ … })

Then you can use the set method:

card.set('number', 2, { operator: 'increment' })

And call .save() to update from there.

This should work, I don't have a complete example of this in the docs but I agree it is a useful use case to demonstrate.

ktwbc commented 10 months ago

Sorry, not creating a new record. I mean just to do an ADD operation on an existing record such as a statistics table where I simply want to increment an existing value by something.

benhutchins commented 10 months ago

Using the the .fromKey method creates an instance of the table class with the given primary key information (hash and range) but it forces Dyngoose to assume the record already exists and it will will force it to save as an update, so on save it will perform a partial update.


// create a new record
const card = Card.new({ id: 1 })

card.title = 'something!'
card.number = 2

// save the new record
await cave.save()
// then later, imagine you don't want to load it:
const card = Card.primaryKey.fromkey({ id: 1 })

// Since we didn't load anything from the database, card has no other attributes on it other than the primary key attributes
console.log(card.title) // null

card.title = 'updated title'
card.set('number', 2, { operator: 'increment' })

await card.save() // will perform an update only on title and number, number will become 4
ktwbc commented 10 months ago

Ah, got it. Thanks!

A suggestion would be to expand the .update() command to avoid having to do 3 functions instead of 1. For example, this is currently the update() command:

 await Users.primaryKey.update({
      hash: id,
      range: undefined,
      changes: {
        status: 'active'
      }
    });

An option would be to use the commands set, add, subtract, etc so that you could issue update() this way:

 await Users.primaryKey.update({
      hash: id,
      range: undefined,
      set: {
        status: 'active'
      },
      add: {
       logins: 1
      }
    });

In other words, these other new methods are added, and "changes" becomes "set" (but would still need to alias "changes" to "set" so it doesn't become a breaking change.) A person could use set, add, subtract together in a single call as above or just individually, examples:

 await Stats.primaryKey.update({
      hash: id,
      range: undefined,
      add: {
        daily_total: 1
      }
    });

 let payment= 50;
 await Accounts.primaryKey.update({
      hash: id,
      range: undefined,
      subtract: {
        remaining_balance: payment
      }
    });

This gives a simple pattern to convert into the actual sdk call. Since you've already used "increment" and "decrement" in other places, for conformity I guess it makes sense to use those instead of add/subtract, or at least alias them.

 let payment= 50;
 await Accounts.primaryKey.update({
      hash: id,
      range: undefined,
      decrement: {
        remaining_balance: payment
      }
    });