I'm using PouchDB + CouchDB to store and sync data in an angular app currently in development. Data is stored per user and contains things such as user authorities/settings, recently viewed content and cart items.
Currently, I have a single CouchDB database that contains a doc for each user. While this structure works well for quickly retrieving user-specific data, it's logically flawed because all user docs are synced to any device that accesses the app. In other words, I ultimately only need the currently logged in user's data to sync.
So, my question is, should I create a Couch database for each user instead of using a single database with a doc for each user? Or is there a better way to go about this?
If you look at the pouchdb-authentication plugin you'll see that you can store metadata for a user in the _user database. That might be all you need.
Related
I am creating an application in which the user can post information as well as choose as a favorite the publication of someone else, when the user performs any of these actions I keep the necessary information in the in the database, specifically in a document where the information linked to the user is found (name, surname, telephone number, etc.).
so when the user logging in the page I get all that information with a single query and I keep it in the LOCALSTOAGE and reduce the queries in the database, then in a different section you can see the publications you have created as well as the ones you have marked as favorites, very similar to what we commonly see in an online store
I'm using angular 6, noje.js and mongoDB. My question is the following:
Is this a correct and effective way to do it?
Should I save it in the database and then perform the corresponding query to obtain it?
shows a screenshot of local storage for explicit use:
As you can see I also save the token that I use to authenticate the user's queries and obviously I do not show your password I would like your opinions.
You never should consider localStorage as an alternative to the database.
At some point, you might have a huge amount of data and your browser would crash to load them.
Bring the data you required from the server.
For some minimum and temporary amount of data, you can consider localStorage. Don't bring all the data in a single query to save database operation. Databases are built to do that for you.
I'm using Azure Mobile Services and I want to clear local database, how can I do that?
I have a problem with my local database. When I logout in app and login with other user, the data of the previous user is loaded for current user and I don't have idea why this occurs. I use debug on server side and the server return correct data, then I believe that the problem is the local Database.
I'm using Azure Mobile Services and I want to clear local database, how can I do that?
For deleting your SQLite file, you could follow Deleting the backing store. Also, you could leverage the capability provided by IMobileServiceSyncTable to purge records under your offline cache, details you could follow Purging Records from the Offline Cache.
When I logout in app and login with other user, the data of the previous user is loaded for current user and I don't have idea why this occurs. I use debug on server side and the server return correct data
Since you did not provide details about your implementations (e.g. user log in/log out, user data management,etc), I would recommend you check whether your server/client side both enable per-user data store. You could use fiddler to capture the network traces when other user logging in, and make sure that the correctly user identifier (e.g. UserId) is returned, then check the query against your local database. Moreover, I would recommend you follow adrian hall's book about Data Projection and Queries.
You can delete all of the local DB files by doing the following.
var dbFiles = Directory.GetFiles(MobileServiceClient.DefaultDatabasePath, "*.db");
foreach (var db in dbFiles)
{
File.Delete(db);
}
However, this would delete all data each time and cause performance issues, as every time after you did this, you'd be getting a fresh copy of the data from your Azure DB, rather than using the cached copy in the device's SQLite DB.
We typically only use this for debugging, and the reason it's in a foreach is to capture all databases created (refer to my last suggestion)
There are a few other things you could try to get around your core issue of data cross-over.
There's another reason you might be seeing this behaviour. With your PullAsync, are you passing it a query ID? Your PullAsync line should look similar to this.
GetAllFoo(string userId)
{
return await fooTable.PullAsync("allFoo"+userId,fooTable.Where(f=>f.userId == userId));
}
Note that the query ID will be unique each time (or at least, for each user). This is used primarilly by the offline sync portion of Azure, but in combination with the Where statement (be sure to import System.Linq), this should ensure only the correct data is brought back.
You can find more information about this here.
Also, some things you may want to consider, store a separate database for each userId. We're doing this for our app (With a company ID) - so that each database is separate. If you do this, and use the correct database on logging in, there's no chance of any data cross over.
I am in the process of designing document storage for CouchDB and would really appreciate some feedback. These documents are to represent "assets".
These databases will also be synced locally to the browser via pouchdb.
Requirements:
Each user can have many assets
Users can share assets with others by providing them with a URI such as (xyz.com/some_id). Once users click this URI, they are considered to have been "joined" and are now part of a group.
Group users can share assets of their own with other members of the group.
My design
Each user will have his/her own database to store assets - let's call it "user". Each user DB will be prefixed with the his/her unique ID.
Shared assets will be stored in a separate database - let's call it "group". shared assets are DUPLICATED here and have an additional field for userId (to indicate creator).
Group database is prefixed with a unique ID just like a user database is prefixed with one too.
The reason for storing group assets in a separate database is because when pouchdb runs locally, it only knows about the current user and his/her shared assets. It does not know about other users and will should not query these "other" users' databases.
Any input would be GREATLY appreciated.
Seems like a great design. Another alternative would be to just have one database per group ("role"), and then replicate from a user's group(s) into their local PouchDB.
That might get hairy, though, when it comes time to replicate back to the server, because you're going to have to filter the documents as they leave the user's local database, depending on which group-database they belong to. Still, you're going to have to do that on the server side anyway with your current design.
Either way is fine, honestly. The only downside of your current approach is that documents are duplicated on the server side (once per user-db and once per group-db). On the other hand, your client code becomes dead-simple, because you don't have to do any filtered replication. If you have enough space on your server not to worry about it, then I would definitely go with your approach. :)
I'm using the CouchDB permission system with per-db-and-user access rights. Each DB represents an app, which are being displayed in a home-screen-like overview and in other places. I need an efficient way to make CouchDB tell me whether a user has access to a db or not - for example a GET /_all_dbs that only returns the DBs for which current user has access. Polling a view or document turns out to be too slow once there are more than a dozen or so apps to display on one page, although I could still tune a view poll with limit=1. Isn't there a better way though?
Query the _security document of the database.
curl http://localhost:5984/db_name/_security
{"admins":{"names":["dbadmin"],"roles":["reader"]},"members":{"names":[],"roles":[]}}
For every database that has admins/users couchdb has a creates a special document called _security that holds a list of all the users for that database. You can make a curl request to that document and get an array that will give you all the admins and members for that database.
Edit
You know your application best but here is a strategy that I think could be helpful? Every couchdb user is stored in the _users database. It is just like any other database. You can create a view on it and then query it. You can even add additional fields to the documents to help with querying. How about when you create a user on a database you update the corresponding document in the _users database as well.
Now if you call _users/_all_docs?include_docs=true you get a list of users along with the databases they have access to. One request and you have everything you need.
I am adding more user profile information to the _users DB in CouchDB. This includes things like first name, last name, etc. This works fine and I'm able to store additional profile information.
How do I get that profile information to be linked in (joined) from another DB's view map function? That is, each document has an author or user field which records the user that created the document. How do I get other profile information about the user included in the view created for this DB?
Unfortunately, you won't be able to join documents across different databases. The closest thing you can have to that is creating copies of user profile information inside your other database, and perhaps using replication to keep that information synchronized.
I'm not sure if there are any plans to have special databases like _users behave differently, but I'm sure there are enough use-cases to make it a worthwhile endeavor. However, there is no mention of this (as far as I've seen) in the Wiki or anywhere else of note.