#Appending to Array using Mutation

21 messages · Page 1 of 1 (latest)

unreal pendant
#

A super simple question but I couldn't find too much on this, I have a data schema for a node which contains a childArray[]. What is the mutation call for appending to an array?

node: defineTable({
    // Array of childNodes
    childNodes: v.array(v.string()),
  })```

For some more context, this is what I have at the moment for my array push function... (syntax is wrong!):
```js
        const node = await ctx.db.patch(args.parentNode, {
            $push: {childNodes: args.childNode},
        });```

Effectively, I need a function that appends a storageId into childNodes :3

Thanks
deep pebble
#

You can read the document, modify the array, then db.replace the document.

#

Convex mutations are transactions; there's no potential for a race condition where another function modifies this document between the read and the write.

unreal pendant
#

That makes sense, so just confirming that means that there are no methods that allow for appending the array directly?

deep pebble
#

Yep, there's nothing built in. If you wanted to write a helper function it might look like

async function addElementToArray(ctx, id, field, value) {
  const doc = await ctx.db.get(id);
  const arr = doc[field];
  if (!Array.isArray(arr)) throw new Error("not an array!");
  arr.push(value);
  await ctx.db.patch(id, {[field]: arr});
}
#

but the TypeScript types are left as an exercise — I wouldn't use this function, I'd write it out normally.

unreal pendant
#

That makes a lot of sense! Thanks so much 😘

tawny walrus
# deep pebble Yep, there's nothing built in. If you wanted to write a helper function it might...

Hi, I am using convex via convex-ents and this is how far I got:

export async function addElementToArray<
  Table extends TableNames,
  Field extends keyof (typeof entDefinitions)[Table]["document"],
>(
  ctx: MutationCtx | QueryCtx,
  id: typeof v.id(), // Pass Table name into that
  value: (typeof entDefinitions)[Table]["document"][Field],
) {}

But I can't figure out how to pass the TableName (Table) to the v.id()

#

Can there be added a helper to convex, convex-helpers or convex-ents? Because anyone here will just copy and paste the code after that and I think a helper would be a nice abstraction for many, especially because after that it can be documented very well in the docs of the package that the function is added to.

tawny walrus
#

Oh hell. I think I found it after all the hours of being stupid:

export async function addElementToArray<
  Table extends TableNames,
  Field extends keyof (typeof entDefinitions)[Table]["document"],
>(
  ctx: MutationCtx | QueryCtx,
  id: Id<Table>,
  value: (typeof entDefinitions)[Table]["document"][Field],
) {}
arctic shadow
#

Curious, is the situation making the "naive" read + update code hard to write? Can you share an example of your callsite?

tawny walrus
arctic shadow
#

Yeah, the example of adding a new value to an array, that makes you want to have addElementToArray

tawny walrus
#

let's say that I have an app similar to discord and I want to give each user roles that's stored as v.array(v.string())

#

and I want to add roles to the user

#

or an array to store all the platforms that a user is on

#

I think you get the idea

#

In my case I refactored the code anyway because I first wanted to store read receipts in an array with clerk ids but I just used an relation to the users table to do that

arctic shadow
#

Yeah, I get that there's a need for updating array fields and adding values, I was just curious whether reading the document first was too cumbersome like this:

const user = ....
await user.patch({roles: [...user.roles, newRole]})
slate yoke