-
Notifications
You must be signed in to change notification settings - Fork 70
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
Index condition does only identify impacted pk on upsert and not on patch or update #366
Comments
I've also noticed I'm having the same issue, I feel like this isn't the expected behaviour. The |
I dug into this today, and I have a fix incoming, but I wanted to bring up a logical issue with your example. It's possible this could be a shorted sided API consideration with the The example update you provided looks like this: entry
.patch({ id: '123', organizationId: '123' })
.set({ effectiveAt: 'n/a', accountId: "123", settledAt: "today" })
.go(); The expectation above is that the In my fix this will be true, however the implementation of this strategy is not sound with the model provided. In its current form, the For example (using your entity), if you create an item with @sam3d My gut is saying if an index |
@tywalch I think you're completely right. Similar to how a composite key is re-computed if any of its attributes change, the What's interesting is that it's more akin to the There's an issue with this – without knowing dependent attributes or the prior state of the entity, during an update operation we don't know when the
Not 100% sure on a good solution here. A few ideas off the top of my head:
condition: (attr) => {
// effectiveAt not changed, don't create OR drop the index
if (attr.effectiveAt === undefined) return null;
// Drop the index if needed
if (attr.effectiveAt === "n/a") return false;
// Otherwise re-create the index
return true;
}, Either way, if we then undergo a state transition because a dependent attribute changed, then the usual |
Actually wait I've been thinking about this some more, this might be more complex than I thought. Going from In the case of the condition going from Is it maybe possible to do some kind of check where if the |
I mulled it around a bit today, but I think I got it; let me know what you think:
Item #1 above is the key to solving the issue you bring up in your first comment, and it's actually what we do currently. This means that Let me know if this doesn't make sense or I am missing anything. I am writing some tests now, but likely won't be making a PR until tomorrow. I'm definitely not looking to rush a change like this. |
I think this makes sense! With the two caveats worth documenting:
{
condition: (attr) => !attr.deletedAt,
pk: { field: "GSI1PK", composite: [] },
sk: { field: "GSI1SK", composite: ["createdAt"] },
}
{
pk: { field: "GSI1PK", composite: ["storeId"] },
sk: { field: "GSI1SK", composite: ["status", "createdAt"] },
}
// Updates GSI1PK, no problem
entity.patch({ id: "29381" }).set({ storeId: "SJR" }).go(); But in order to perform the same operation with a {
condition: (attr) => attr.status !== "deleted",
pk: { field: "GSI1PK", composite: ["storeId"] },
sk: { field: "GSI1SK", composite: ["status", "createdAt"] },
};
// Condition returns true, so we need to set GSI1PK and GSI1SK in case the index
// doesn't already exist. We now MUST provide status and createdAt
entity.patch({ id: "29381" }).set({ storeId: "SJR" }).go();
// So this must be done instead every time
entity
.patch({ id: "29381" })
.set({ storeId: "SJR" })
.composite({ status: prevEntity.status, createdAt: prevEntity.createdAt })
.go(); |
DynamoDB doesn't propagate to a composite index unless both attributes are present, right? So to remove an entity from a sparse index you technically don't have to drop both, just one of them. Maybe the result of |
My gut is that the user would determine if they wish to check attributes outside the composite; i.e. that Electro would continue to supply the
This is a very, very good point. You're saying that because this could be the first time the Great catch! This is sort of the opposite of the issue I brought up above, I had not considered this 🤯
How might this work?
Do you think this problem becomes "solved" by adding this requirement? It sort of seems like it? That said, this will be difficult for newbies to understand, not to mention this would become a request time validation which makes it doubly hard for users to anticipate. While it does feel like we're close to solving this, I don't want to be too precious about the current API for handling this. I haven't squared the circle in my mind, but this topic does feel like it could have a meaningful overlap with Ross Gerbasi's request for the ability to I sat down recently and thought about what that API would look like. Creating an API for dropping an index was very straight forward, but I found an API for building a specific index had a lot complexities due to potential attribute dependencies. The simplest approach would be to simply accept composite values "as-is" (i.e. without any setter processing) and add an automatic Thinking through that feature had me thinking there must be some kind of third way. Does this spark anything in you? |
Hey @tywalch so I must admit I haven't spent much time thinking about a broader API and requirements of the library. I have no doubt this is much more complex. We would be good with a very specific The use case we are looking to handle is one where attributes already exist in an Not sure how much this connects with the We would also need to keep our createdAt: {
type: 'string',
readOnly: true,
required: true,
default: getNowISO,
set: getNowISO,
},
updatedAt: {
type: 'string',
watch: '*',
required: true,
default: getNowISO,
set: getNowISO,
}, |
I ran into this issue today as well as I'm new to ElectroDB but using sparse index pretty heavy. My use-case is similar to what have been said by others already.
and I just want to have ACTIVE ones in the GSI1 index and get removed once I update the state. Any idea if there will a fix soon? Or is there any workaround? |
Small update: this is still a WIP, I made significant progress this afternoon, still ironing out tests for edge cases 👍 |
GH Closed this issue because I merged a fix, but I'm reopening it to keep discussion open in case there are any issues. @nonken You can see the impact by using the original playground link you provided 👍 |
@tywalch this is so good, thank you a million times for diving into this. Can we somehow donate, as in, does the sponsoring work for you? |
No problem, glad it worked and I'm happy you raised this because it helps everyone! Yup, I'm setup for sponsoring via GitHub's native sponsoring option (if that works) -- thank you so much for considering me for sponsorship! |
Closing, but feel free to reopen! |
This update unfortunately started causing issues for us. One example use case would be something like this
previously we had a sparse index for accessing chats by user id (see example entity definition below), and it worked well with v2.13.1. For instance, if a user logs in while having an active chatsession, the unauthenticated chat session is correctly added to the "byUser"-index when the "loggedInUserId" attribute is set (for unauthenticated users it is undefined). It seems this is no longer supported, or is there some way to still achieve this? The upsert operation we used to create/update the message entries started failing, which was unexpected for a minor version upgrade. I believe this is a valid use case for sparse indices, and it's unfortunate if the library no longer supports it.
|
A bug was discovered that the logic to validate the presence of an attribute was a simple falsey check instead of a check that the value was `undefined`. This caused empty strings, zero values, and the boolean value `false` to incorrectly be considered missing
* Further fixes in service of Issue #366 A bug was discovered that the logic to validate the presence of an attribute was a simple falsey check instead of a check that the value was `undefined`. This caused empty strings, zero values, and the boolean value `false` to incorrectly be considered missing * Fixes test
Hi @severi Firstly, I want to say that I am sorry your existing code broke do to this fix. I try very hard to make sure this does not happen. Ultimately in choosing between a As for how you might achieve what you had, I have two potential approaches for you:
Again, please accept my apology for the unexpected errors in your app, and let me know if any of the above will work for you; If the above won't work in your case, I can work to maybe create an escape hatch (via an execution option or some type of configuration) for this requirement. |
Describe the bug
I have the following index:
When updating an item using
.update
the resulting DynamoDB query only hasgsi3sk
set and notgsi3pk
. When making the same call using.upsert
it works, but I need to provide all available fields which requires me to fetch the item first.I dug in a bit deeper and it looks like that _getIndexImpact will not return the
pk
in my case because organizationId is not provided in the attributes. Thesk
does get set resulting in a record without apk
.It can be that I am not understanding the intend correctly, but my expectation was that this would work for update or patch calls.
ElectroDB Version
2.13.1
ElectroDB Playground Link
Playground
Entity/Service Definitions
Include your entity model (or a model that sufficiently recreates your issue) to help troubleshoot.
Expected behavior
I am unsure what the correct way of using
condition
here is.The text was updated successfully, but these errors were encountered: