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

suggestion: Deno.Kv.count() #18965

Open
iuioiua opened this issue May 3, 2023 · 3 comments
Open

suggestion: Deno.Kv.count() #18965

iuioiua opened this issue May 3, 2023 · 3 comments
Assignees
Labels
ext/kv Related to "Deno.openKv()" API suggestion suggestions for new features (yet to be agreed)

Comments

@iuioiua
Copy link
Contributor

iuioiua commented May 3, 2023

This would be useful for cases where one would like to know how many entries exist for a given prefix without processing/storing any of the actual data. Example:

const count = await kv.count({ prefix: ["posts"] });

I know this can be done using kv.list(), but having an in-built method seems useful.

@cdoremus
Copy link

cdoremus commented Aug 3, 2023

I totally support this proposal, but in lieu of the function that @iuioiua proposes, you could use the sum() function when inserting data in KV. Here is an example:

const users = [
  {
    "id": 1,
    "name": "John Doe",
    "age": 25,
  },
  {
    "id": 2,
    "name": "Emma Smith",
    "age": 32,
  },
  {
    "id": 3,
    "name": "Michael Brown",
    "age": 40,
  },
  {
    "id": 4,
    "name": "Sophia Jackson",
    "age": 19,
  },
  {
    "id": 5,
    "name": "William Davis",
    "age": 37,
  },
  {
    "id": 6,
    "name": "Olivia Miller",
    "age": 22,
  },
  {
    "id": 7,
    "name": "Barbara Jones",
    "age": 17,
  },
  {
    "id": 8,
    "name": "Craig Sampson",
    "age": 33,
  },
];

const kv = await Deno.openKv();
// Insert users and keep track of the count
for (const user of users) {
  const u64 = new Deno.KvU64(1n);
  const result = await kv.atomic()
    // check() not called since this is an insert
    .set(["user", user.id], user)
    .sum(["count"], u64.value) // count incremented by one
    .commit();
  if (!result.ok) {
    throw new Error(`Problem persisting user ${user.name}`);
  }
}

// Retrieve the count from KV
const count = Number((await kv.get(["count"])).value);
console.log("Count: ", count);

@iuioiua
Copy link
Contributor Author

iuioiua commented Aug 3, 2023

To add to Craig's alternative solution, examples can be seen in Deno SaaSKit's KV logic.

@talltyler
Copy link

I don't mind this solution to manage our own sums but I think we need a way to get at the result of the action without making an additional get. This is what I'm doing now.

async function increment(key, amount=1) {
  await kv.atomic()
    .mutate({
      type: 'sum',
      key: key,
      value: new Deno.KvU64(BigInt(amount)),
    })
    .commit();
  const data = await kv.get(key);
  return Number(data.value?.valueOf())
}

From my understanding based on the way it works if you call this increment function multiple times you could end up with race conditions because the get could be returning the sum of a different call. Is this true?
Could we maybe change it to be something like this where the values are optionally returned in a Dictionary or something?

async function increment(key, amount=1) {
  const data = await kv.atomic()
    .mutate({
      type: 'sum',
      key: key,
      value: new Deno.KvU64(BigInt(amount)),
    })
    .commit({returnValues:true);
  return Number(data[key]?.value?.valueOf())
}

or maybe better if they the results of one atomic action could be chained to the next...

async function create(key,data) {
  const action = kv.atomic();
  action.mutate({ // auto increment id
    type: 'sum',
    key: ['counts', ...key],
    value: new Deno.KvU64(1n),
  }).then((result) => {
    const id = result.value?.valueOf();
    action.set([...key, id], data)
  });
  return await action.commit();
}

I understand this introduces the need to rollback changes if something fails in the middle which could be more complicated to build but this would also be much more powerful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ext/kv Related to "Deno.openKv()" API suggestion suggestions for new features (yet to be agreed)
Projects
None yet
Development

No branches or pull requests

6 participants