cyremur
cyremur4w ago

Index on optional nested properties

Is there a reason that on the schema:
export const vGameState = v.object({
playerOne: v.optional(
v.object({ userId: v.id("users"), username: v.string() })
),
playerOneId: v.optional(v.id("users")),
playerTwo: v.optional(
v.object({ userId: v.id("users"), username: v.string() })
),
playerTwoId: v.optional(v.id("users")),
});
export const vGameState = v.object({
playerOne: v.optional(
v.object({ userId: v.id("users"), username: v.string() })
),
playerOneId: v.optional(v.id("users")),
playerTwo: v.optional(
v.object({ userId: v.id("users"), username: v.string() })
),
playerTwoId: v.optional(v.id("users")),
});
with indices
export default defineSchema({
games: defineTable(vGameState)
.index("by_player_one", ["playerOneId"])
.index("by_player_one_nested", ["playerOne.userId"])
.index("by_player_two", ["playerTwoId"])
.index("by_player_two_nested", ["playerTwo.userId"]),
});
export default defineSchema({
games: defineTable(vGameState)
.index("by_player_one", ["playerOneId"])
.index("by_player_one_nested", ["playerOne.userId"])
.index("by_player_two", ["playerTwoId"])
.index("by_player_two_nested", ["playerTwo.userId"]),
});
I can do
const games1 = await ctx.db
.query("games")
.withIndex("by_player_one", (q) => q.eq("playerOneId", userId))
.order("desc")
.collect();
const games1 = await ctx.db
.query("games")
.withIndex("by_player_one", (q) => q.eq("playerOneId", userId))
.order("desc")
.collect();
But the nested one gets a type error?
const games1_nested = await ctx.db
.query("games")
.withIndex("by_player_one_nested", (q) =>
q.eq("playerOne.userId", userId)
)
.order("desc")
.collect();
const games1_nested = await ctx.db
.query("games")
.withIndex("by_player_one_nested", (q) =>
q.eq("playerOne.userId", userId)
)
.order("desc")
.collect();
No description
4 Replies
deen
deen4w ago
It's because the playerOne object is optional in your schema. The error message is confusing. The "undefined" is playerOne when it is missing. You can't read a property from an object that doesn't exist.
sshader
sshader3w ago
Hmm pretty sure the types are just wrong here -- I'll work on a fix. In the meantime, a type cast to get around it userId as any or a // @ts-expect-error should unblock you (and you can verify you get the results you expect) The mental model I use for indexes is that on every document insertion / change, we look up the values for each field path listed in the index, and essentially create a tuple that we can sort by (the index key). So documents without playerOne will have playerOne.userId as undefined
cyremur
cyremurOP3w ago
Maybe I'm too spoiled by ?. but I expected both variants to resolve to Id<"users"> | undefined
deen
deen3w ago
Yeah I thought you were spoiled too, but looks like you were right! Nice one 😁