-
Notifications
You must be signed in to change notification settings - Fork 1
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
scoped stores and the type property #106
Comments
ping @hoodiehq/maintainers I would love to hear your thoughts on this ^^ It’s a discussion on a significant Hoodie Client API change, something we have to get right now, so we avoid changes in the future, especially ones that would imply changes in how documents are stored / retrieved |
I don't know couchdb very much, could you explain why is that? CouchDB doesn't play well with secondary indices? Performace? Well, until the middle I was thinking "we don't really need to change the API for that do we? We can make hoodie use the _id rather than type behind the curtains, right?". But then the I believe nested stores like that are a very important use-case, which I've needed myself in offline-first apps in the past, and the So... yeah, this works for me 👍 |
Performance and harddrive usage. I’m sure there are great resources on that topic out there, but don’t know out of my head. Maybe @janl can point us to some? |
I still don't understand yet, how it goes with the rest of the API and so can't offer any suggestion on this.
the scope shouldn't be easy to change. Maybe a move API which drops and recreates it with another
I think the slash (/) should be internal implementation details communicated how it's stored/used under the curtain. |
Well I'm inclined to trust the pros on this one, as I don't personally have a lot of experience with the performance impacts attributed to secondary indexes. I'm also not opposed to the use of the slashes, but think we need to keep the sausage factory doors closed as much as possible - as these implementation details can be confusing for the typical targeted developer. In the end, the same goal is achieved and if scaling is improved, that's a plus for everyone. Clearly its a matter of coming up with an understandable way of documenting it, or abstracting that complexity away. Unfortunately, I'm straining my brain to come up with another option. :/ |
My thoughts (as a relative CouchDB newbie): My preferred terminology as opposed to 'Prefix' would be 'Namespace' e.g. I'd like this API to be extendible with extra arguments in the same way as, for example, Node's |
I like What I like about the word "prefix" is that it makes clear that it is still a part of the If you are interested in playing around with it, I made a quick-and-dirty implementation of the |
I like the idea with the multiple arguments too. When you say namespace are you referring to the properties on the other issue about where to put hoodie generated properties? |
no this is just about the |
|
I also prefer |
I'm glad the multiple arguments idea has been well received! Apologies, @pmbanugo about the confusion with the 'namespace' terminology, I missed that conflict between the Of course we don't want to hide the fact that, as part of the implementation for CouchDB, the id is prefixed with it's address to make retrieval easier; however my advocacy for the terminology 'Namespace' (or something else) over 'Prefix' is based around leaving some abstraction of the implementation from the API. If at some point in the future hoodie starts using an alternative DB engine, or CouchDB is changed in some way, so that retrieving store objects with a particular object address (a.k.a prefix, a.k.a namespace) is possible using a more performant way than including it in the |
I gave this some more thought. No breakthrough :) but maybe it helps to share: I really like the idea of passing in multiple arguments (or an array of strings) as segments of the id prefix, so that we can leave out the hoodie.store.withIdPrefix('list') // matches all documents with IDs starting with "list/"
hoodie.store.withIdPrefix('list', 'uuid567','item') // matches all documents with IDs starting with "list/uuid567/item/" The downside is that I can think of cases where I want to listen to changes in both the list document as well as all its items. But I don’t mind finding a better name that
With var list = {id: 'list/uuid123', title: 'shopping list'}
var listNamespace = hoodie.store.namespace(list)
listNamespace.on('change', handleListAndItemChange) This API could workaround the problem I mentioned above with the trailing |
relevant discussion from PouchDB slack |
To sum this up a little. Using the document Especially, these ”some types” are very common ones and they are solved by what is called internally as the “by-id” index. You know this as The biggest advantage here is that C/PouchDB need this index internally, so it is always there and implementations will try to make sure it is most efficient. Essentially, any queries we can handle using this index, we get ostensibly for free. What’s in an index?There are two main modes of operation for an index:
PouchDB-NextNow from the quoted Slack discussion above. There is a slow moving project inside PouchDB that would make secondary index creation A LOT more efficient than it is today. Like a lot a lot, like even better than CouchDB does it. The downside is: we can’t bet on it just yet. This is a work in progress, it won’t be as widely cross-platform/storage as the current PouchDB implementation and only supported IndexedDB. In fact, not supporting different storage backends like WebSQL etc. is what makes index creation performance A LOT better. Some cross-platform/storage compatibility could be added later of course. The main point here is though: this is going to take a while.
|
One more thing: on the flip-side, if we have a flexible and efficient |
Amazing comment 👏
Yes, we can ignore these. These problems are more related to the fact that
The main motivation for the current I think the question about querying is out of scope here and should be addressed separately? The scoped APIs (or however we want to refer to them) are not only about finding data, but also about creating / updating and about listening to changes. |
So solving this is an implementation detail (not to diminish the work to fix it, but conceptually, we know how to fix this)?
That makes perfect sense. Maybe we should adopt “collection” for this?
For now I’d like to at least understand how these two will interoperate. Should users be able to make a query on a collection (very nice feature, not easy to implement, but probably doable) just like they would query all their data (very easy with native PouchDB indexing), or would we have the latter only? We can figure out all the nasty details later, I just want to understand your thinking here. |
Just want to say: I very much enjoy this discussions about Hoodie APIs <3 I’m sure something great will come out of this.
Yes, but it will be a breaking change, we can’t solve it with the current API I think. Instead of
Calling it What I like about
I would have a query API on the root API only (just like I wonder if it would be helpful to come up with a few different use app examples, for which we would list the different type of documents we need to store and access. Then we could create dream code for the different API suggestions and see how they compare? It would certainly take some effort, but maybe it will make a good base of discussion that we can keep up-to-date as the discussion evolves, and helps more community members jump in at any point? |
We had some discussion on this with @janl while we have been at the CouchDB Dev Summit. Our recommendation is to go ahead with Our thinking is that it’s not the first API that one would use when familiarizing with Hoodie. A person new to Hoodie would use the base We have a PR ready at hoodiehq/pouchdb-hoodie-api#124, we’d love a review 👀 |
on it’s way via hoodiehq/pouchdb-hoodie-api#124 |
The current Hoodie Client provides a convenience method to get a store API which is scope to documents with the
.type
property set to the passed scopeThe problem with the
.type
property is that people might use it for other things than scoped stores. We decided to work around this with a lot of effort, among others we had to implement virtual add / remove events when a user changes the.type
propertyWe made all this in the spirit of Dreamcode, we discussed what the nicest possible API would be and then tried to make it work backwards. And we did.
Shortcomings
Implementing the above APIs adds a lot of complexity and has lead to many very tricky to find errors in the past. For example hoodiehq/hoodie#612 and hoodiehq/hoodie-store-client#95
Another major problem is that this behavior is confusing and not predictable. Today I think we tried to be too smart. People don’t really understand what the
hoodie.store(scope)
API does, how it behaves and how it goes together with the rest of thehoodie.store.*
APIs.But maybe the biggest problem a.k.a. learning I had in the past based on many discussions with the Hoodie Community and people from other projects: a simple API is not helpful if it does not scale. It’s not enough to create Dreamcode for people to get going quickly. It must remain clear and usable, even as the application grows in complexity and usage. And I think in that regard we failed. Not only because of confusing, complexity and bugs, but because we did not embrace the Nr. 1 tip when it comes to storing data using PouchDB / CouchDB: use the
_id
property as much as possible for querying, to avoid secondary indices as much as possible.I’m working with CouchDB since over 5 years now, and I have not worked on a single project that does not use the
_id
properties to big extend in order to make the apps and analytics as performant as possible. All projects where we use PouchDB / CouchDB, we would definitely decide to store the above document with_id
prefixes, like"_id": "todo/uuid567"
. Yes that means that the "scope" cannot be changed, but that is by design. Using the.todo
property was a bad design decision.I’d like to hear all your thoughts on this, but I think we should come up with something better now, because a change will result in requiring to change every single document stored by Hoodie apps, and we better do this before there are more apps in production.
Embracing the primary index
I think we better embrace the best practise of using the
_id
property from the beginning in Hoodie, with good documentation, API design and mental models, instead of trying to hide away. For the most simple applications people won’t probably need to use it, but for more complex one there should be a clear API.I thought a lot about this and my recommendation is we remove the
hoodie.store(scope)
API entirely in favor ofhoodie.store.withIdPrefix(prefix)
. Example:In most ways it will work very similar to
hoodie.store(scope)
, without the need of a.type
property. We don’t need to explain that theid
property is special and that it cannot be change, only trough removal and re-creation with a new one. And I think that the meaningprefix
is clear to most and can be quickly looked up by others..withIdPrefix
is fairly self-explanatory, it tells me that all APIs that it returns imply the givenidPrefix
.Here are a few things that I don’t find ideal and maybe together we can come up with a smart way to workaround it, or maybe a good documentation has to do
/
fromtodo/
and make it an internal implementation detail. But on the other side, I think it’s okay to document and explain that using/
as separator is the recommended way by Hoodie apps_id
prefix is often times used for one-to-many relations. Say my todo app has both lists and todos that belong to the lists. Best practise would be to have id’s like"_id": "list/uuid567"
for the lists and"_id": "list/uuid567/todo/uuid8910"
for the todos that belong to that list (unless moving items is very common, but let’s leave that out of scope for this example). Now I no longer can find all lists only withhoodie.store.withIdPrefix('todo/').findAll()
, the result would also include all todos. I have no simple solution to this. But maybe this is such advanced usage that Hoodie can clearly explain both the best pratises and the.withIdPrefix
API, and it’s up to the developers to filter out the minutes themselves. It is a feature after all to get a list and all its todos with something likehoodie.store.withIdPrefix('list/uuid567').findAll()
. Or maybe we want to add an extra property which would allow us to query the list documents only. See also the suggestion in Store: Hoodie properties added to documents #105 which would give us a namespace so there no longer would be a conflict with document properties used by the app.This is how far I got, I’d love to hear your thoughts on this :)
The text was updated successfully, but these errors were encountered: