I am using MongoDB with Node for a relatively simple web application that involves users signing up and authenticating their login information. I have experience with relational DB's, but am fairly new to the NoSQL game. I am wondering if I am efficiently using the NoSQL database with the current format of my data storage?
My code as of now to save a user looks like so:
db.users.save({email: req.body.email, display_name: req.body.displayName, password: req.body.password}, function(err, saved) {
if( err || !saved )
console.log("User not saved");
else
console.log("User saved in MongoDB");
});
What is happening here is that each user is being generated his or her own document in a MongoDB "collection." I am wondering if this is going to slow things down when the user base becomes relatively large, and I need to quickly find users for authentication?
Any answer that can help me out conceptually or point me in a direction to learn more would be greatly appreciated!
In MongoDB, what's right and what's wrong depends mostly on how you are going to interact with your data. But one document per user seems like a viable strategy for most use-cases.
To speed up retrieval of users, remember to add indexes for those fields you want to retrieve them by.
In this case, the document you save has no _id field. That means a new document will be generated with a newly generated _id, even when there is already an entry with the same values in the database. Is this what you want? When you want to use the .save(doc) function for updating an existing document, you need to have the _id of the document with the same value as the one you want to update.
Related
I am developing a simple client for Android which fetches data from a CouchDB database. There will be only one database for all users. The data pull-replicated is filtered by a JS function. Such function (simplified) would be like this:
function(doc,req) {
if (!doc.type || doc.type !='item') { return false; }
if (doc.foo && ... && req.userCtx.bar.indexOf(doc.foo) != -1) { return true; }
...
}
As I have read in the official documentation, _users is a perfect place to set custom fields related to the user. So did I as you can see in the above code (see req.userCtx.bar array).
The problem I am facing is that the object/JSON req.userCtx only contains these fields: db, name and roles.
1. What would be a good alternative to my idea? I am a little bit stuck right now at this point. 2. How can I retrieve the user's data (all fields official and custom)?. 3. Is it correct to add as filter parameter a large array?
NOTE
I am thinking of a messy alternative of adding an array-field in every item which will contain the list with all users allowed to pull such item although I have the feeling that there must be another way.
Saving user data in _users is interesting because only the user or an admin can read a user's document.
However, as you've found out, that doesn't mean that all user data is available to the userCtx object. All you get is the user's name and roles array. Can you make do with roles?
To retrieve all of the user's data, you should fetch the user's document from the _users database. You can do that with a GET request on http://localhost:5984/_users/org.couchdb.user:[USER].
To know what would be an appropriate solution to your problem, we'd need quite a bit more info. For instance, looking at your code, it seems you designed that filter with the intention of restricting replication to documents listed as being visible to the user. However, you can't really lock down CouchDB in a way that replication works, and the user doesn't have read access to the entire database. You really need one db per user for this to work.
Ok so I have a pretty simple DB setup in a MEAN app (node, mongoose, mongo) where I have Book records, and User records. A book has a single Owner, and can have any number of shared users which are stored in an array in a field called sharedWith:. Originally I was storing the user records with an email address as the _id field. I now realize this was a dumb move on my part because if someone wants to change their email address it effectively cuts them off from their books.
The app is not live yet, so it's not a fatal mistake.
My question is, once I revert the User documents to using the original hash value for _id, and store those in the Owner and sharedWith fields in the book documents, will I have to query each hash just to retrieve the actual usable user data?
I know mongoose has a .populate() method which will resolve sub documents, but as for inserting them? Will I POST the users as email addresses, then query each and store the resulting hashes? I can do this manually, but I wanted to make sure there is not some secret mongo-sauce that can do this in the DB itself.
Thanks!
If you have the _id available in the frontend for the user. You can directly share him a book by adding the _id to the sharedWith array of a book. But if you don't have the _id of the user available in the frontend, you need to manually get the _id by querying with the email and then store the _id in the sharedWith. As to retrieve the books, populate is indeed the best option to use to get user data.
And to get all books shared with a user you can do something like this,
Book.find({sharedWith:user1._id},function(err,docs){ });
This query can be made efficient if you use an index on sharedWith but that depends on your use case.
OK this should be fairly simple so I think I may be doing a thinking mistake.
I have an existing document. I serve it to the client, together with its ObjectId. The client modifies, and wants to update the document. So it comes with the id - looks to me a good choice to identify which document I want to update (?).
But I get an error:
[MongoError: Mod on _id not allowed]
This is the code which updates (via HTTP PUT):
id = req.body._id
Item.update({'_id': id }, req.body, (err) ->
So you need to remove the _id key from the "update" object you send. _.omit can facilitate this.
Item.update {_id: req.body._id}, _.omit(req.body, '_id'), (err) ->
Aside: I see people code like this often. Taking input from the browser and just shoving it into your database is a terrible idea from a data integrity and security perspective. Just like most businesses don't just leave their accounting ledgers out on the counter with a pen and ask the customers to write in there unsupervised. Consider enforcing your data schema, authorization, and some validations.
I'm trying to wrap my head around CouchDB. I'm trying to switch off of MongoDB to CouchDB because I think the concept of views are more appealing to me. In CouchDB it looks like all records are stored in a single database. There is no concept of collections or anything, like in MongoDB. So, when storing different data entities such as users, blog posts, comments, etc, how do you differentiate between them from within your map reduce functions? I was thinking about just using some sort of type property and for each item I'd just have to make sure to specify the type, always. This line of thought was sort of reinforced when I read over the CouchDB cookbook website, in which an example does the same thing.
Is this the most reliable way of doing this, or is there a better method? I was thinking of alternatives, and I think the only other alternative way is to basically embed as much as I can into logical documents. Like, the immediate records inside of the database would all be User records, and each User would have an array of Posts, in which you just add all of the Posts to. The downside here would be that embedded documents wouldn't get their own id properties, correct?
Using type is convenient and fast when creating views. Alternatively you can consider using a part of the JSON document. I.e., instead of defining:
{
type: "user",
firstname: "John",
lastname: "Smith"
}
You would have:
{
user: {
firstname: "John",
lastname: "Smith"
}
}
And then in the view for emitting documents containing user information, instead of using:
function (doc) {
if (doc.type === "user") emit(null, doc);
}
You would write:
function (doc) {
if (doc.user) emit(null, doc);
}
As you can see there is not much difference. As you have already realized 1st approach is the most widely used but second (afaik) is well accepted.
Regarding the question of storing all Posts of one User in one single document. Depends on how you plan to update your document. Remember that you need to write the whole document each time that you update (unless you use attachments). That means that each time a user writes a new Post you need to retrieve the document containing the array of Posts, add/modify one element and update the document. Probably too much (heavy).
i have one conceptual question about designing data model in mongo db.
I have some record for "lists". Each list is "one row" record with id, descr, createdBy etc. fiels. But now i have a requirement that each "list" can be shared with other users. What is the best way to design/re-design the model so when user login to see "lists" that he created and "lists" that was shared with him? I was thinking of creating new field "sharedWith" in which all usernames with which "list" is shared to be put separated with comma(or something else). And then when request is made to search in this field. But somehow this approach doesn't seem to me very useful. Can you give me some advice or guidelines ?
I'm using nodejs with mongoose.
Thanks!
User: {
...
myLists: Array<ListObject>
sharedLists: Array<ListObject>
};
ListObject: {
...
owner: User,
sharedWith: Array<User>
};
That would seem a sensible design to me.