CouchBase Member Login - nosql

Could anyone provide me with a great explination or tutorial around a user management couchbase database.
With SQL login would be
SELECT * FROM users WHERE email = :email AND password = :password
How would this work in couchbase, assuming my user document looks like this
{
"uid": "3",
"email": "dummy#example.com",
"password": "6a1644c781989cb3f47c8a38a0e75c6c",
"name" : "John Doe",
"jsonType" : "user"
}
My View at the moment is
function (doc, meta) {
if(doc.jsonType == "user"){
emit([doc.email, doc.password], [doc]);
}
}
And I can goto
http://localhost:8092/default/_design/dev_users/_view/login?stale=false&connection_timeout=60000&limit=10&skip=0&key=[%22dummy#example.com%22,%226a1644c781989cb3f47c8a38a0e75c6c%22]
which returns
{
"total_rows":3,"rows":
[{
"id":"user::3",
"key":["dummy#example.com","6a1644c781989cb3f47c8a38a0e75c6c"],
"value":
[{
"uid":"3",
"email":"dummy#example.com",
"password":"6a1644c781989cb3f47c8a38a0e75c6c",
"name" : "John Doe",
"jsonType" : "user"
}]
}]
}
I would just like advice on if I am approaching this the correct way. I am very new to couchbase. I have googled this but can't seem to find exactly what I'm looking for. Any help appreciated to get me off to a good start.

In noSQL(key/value) you have to pay special attention to the KEY structure design. In your case you should identify what is your loginID? Is it "email" field? If so, you can create a key based on that. e.g.
KEY: "dummy#example.com"
VALUE:
So then when user enters user id/password you can simply call one GET operation from the couchbase.
If no such loginID exists, you will not get any json value.
If loginID exists, then you will get back json document that you can use to check password and also (in case password matches) populate user specific data from that json in your login session.
NOTE: I assume you are not storing clear passwords in json, but instead using password digest with salt.
So no view functionality required here.
As for views usage, I highly recommend reading though "Basic Couchbase querying for SQL people"
also read on Creating an e-commerce platform with Couchbase 2.0

I would suggest not including the whole document in the index - i.e. change your emit to something like:
emit([doc.email, doc.password])
This will minimise the size of (and hence time taken to operate on) the index. If you later need the actual doc contents you can use a normal get operation to fetch it, using the id field of the query row. Some of the SDKs provide a method to perform this for you, for example setIncludeDocs() in the Java SDK.
Other than that this looks pretty reasonable. A detailed overview of Views is included in the Couchbase developer guide. Another good resource for complete example applications (above the standard getting started tutorials) is: http://couchbasemodels.com

Related

NoSQL db schema design

I'm trying to find a way to create the db schema. Most operations to the database will be Read.
Say I'm selling books on the app so the schema might look like this
{
{ title : "Adventures of Huckleberry Finn"
author : ["Mark Twain", "Thomas Becker", "Colin Barling"],
pageCount : 366,
genre: ["satire"] ,
release: "1884",
},
{ title : "The Great Gatsby"
author : ["F.Scott Fitzgerald"],
pageCount : 443,
genre: ["Novel, "Historical drama"] ,
release: "1924"
},
{ title : "This Side of Paradise"
author : ["F.Scott Fitzgerald"],
pageCount : 233,
genre: ["Novel] ,
release: "1920"
}
}
So most operations would be something like
1) Grab all books by "F.Scott Fitzgerald"
2) Grab books under genre "Novel"
3) Grab all book with page count less than 400
4) Grab books with page count more than 100 no later than 1930
Should I create separate collections just for authors and genre and then reference them like in a relational database or embed them like above? Because it seems like if I embed them, to store data in the db I have to manually type in an author name, I could misspell F.Scott Fitzgerald in a document and I wouldn't get back the result.
First of all i would say a nice DB choice.
As far as mongo is concerned the schema should be defined such that it serves your access patterns best. While designing schema we also must observe that mongo doesn't support joins and transactions like SQL. So considering all these and other attributes i would suggest that your choice of schema is best as it serves your access patterns. Usually whenever we pull any book detail, we need all information like author, pages, genre, year, price etc. It is just like object oriented programming where a class must have all its properties and all non- class properties should be kept in other class.
Taking author in separate collection will just add an extra collection and then you need to take care of joins and transactions by your code. Considering your concern about manually typing the author name, i don't get actually. Let's say user want to see books by author "xyz" so he clicks on author name "xyz" (like some tag) and you can fetch a query to bring all books having that selected name as one of the author. If user manually types user name then also it is just finding the document by entered string. I don't see anything manual here.
Just adding on, a price key shall also fit in to every document.

How to query username from userId in a collection in Meteor?

I am trying to implement a basic search bar functionality in my app.
I have a bunch of articles, and everyone has an owner. This is specified by the userId in the user parameter of each article.
Right now I can search for keywords within the article, the title, and the date. However I want to be able to query for the username of the author of the article, but I only have the userId available to me...
var keyword = Session.get("search-query");
var query = new RegExp( keyword, 'i' );
var results = Articles.find( { $or: [{'user': query}, // this is only searching userId of the author!
{'title': query},
{'articleText': query},
{'datetime': query}] } );
return {results: results};
I'm not sure how to do this...
Welcome to non-relational databases! You're coming from an RDBMS environment so you expect joins. There are none. Store the username in the article it belongs to, then yes, if a user change their username, you'll need to loop through the collection and update the username where the _id matches.
Please look here for mongo strategies (this isn't Meteor-specific at all): http://docs.mongodb.org/manual/core/data-modeling/
PS: If you get eye haemorrhaging whenever you look at your schema-which-actually-really-isn't-one, you can still give https://github.com/erundook/meteor-publish-with-relations a go - but note that under the hood it's going to get even 'worse' (have a look at your mongo opslog). Publish with relations is only there for convenience and ease of programming, not performance.
Good luck!
So I guess you'd have to either save the username as well as it's own field (or put both id and username in a user object), or search the Users collection for valid usernames, and when you found one use its id to search the Articles DB.
The first suggestion would probably be way more efficient I guess.
That's pretty easy, assuming you're doing the search on the server which has access to all the users:
var username = Meteor.users.findOne(userId).username;

How do I describe a collection in Mongo?

So this is Day 3 of learning Mongo Db. I'm coming from the MySql universe...
A lot of times when I need to write a query for a MySql table I'm unfamiliar with, I would use the "desc" command - basically telling me what fields I should include in my query.
How would I do that for a Mongo db? I know, I know...I'm searching for a schema in a schema-less database. =) But how else would users know what fields to use in their queries?
Am I going at this the wrong way? Obviously I'm trying to use a MySql way of doing things in a Mongo db. What's the Mongo way?
Type the below query in editor / mongoshell
var col_list= db.emp.findOne();
for (var col in col_list) { print (col) ; }
output will give you name of columns in collection :
_id
name
salary
There is no good answer here. Because there is no schema, you can't 'describe' the collection. In many (most?) MongoDb applications, however, the schema is defined by the structure of the object hierarchy used in the writing application (java or c# or whatever), so you may be able to reflect over the object library to get that information. Otherwise there is a bit of trial and error.
This is my day 30 or something like that of playing around with MongoDB. Unfortunately, we have switched back to MySQL after working with MongoDB because of my company's current infrastructure issues. But having implemented the same model on both MongoDB and MySQL, I can clearly see the difference now.
Of course, there is a schema involved when dealing with schema-less databases like MongoDB, but the schema is dictated by the application, not the database. The database will shove in whatever it is given. As long as you know that admins are not secretly logging into Mongo and making changes, and all access to the database is controller through some wrapper, the only place you should look at for the schema is your model classes. For instance, in our Rails application, these are two of the models we have in Mongo,
class Consumer
include MongoMapper::Document
key :name, String
key :phone_number, String
one :address
end
class Address
include MongoMapper::EmbeddedDocument
key :street, String
key :city, String
key :state, String
key :zip, String
key :state, String
key :country, String
end
Now after switching to MySQL, our classes look like this,
class Consumer < ActiveRecord::Base
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :consumer
end
Don't get fooled by the brevity of the classes. In the latter version with MySQL, the fields are being pulled from the database directly. In the former example, the fields are right there in front of our eyes.
With MongoDB, if we had to change a particular model, we simply add, remove, or modify the fields in the class itself and it works right off the bat. We don't have to worry about keeping the database tables/columns in-sync with the class structure. So if you're looking for the schema in MongoDB, look towards your application for answers and not the database.
Essentially I am saying the exactly same thing as #Chris Shain :)
While factually correct, you're all making this too complex. I think the OP just wants to know what his/her data looks like. If that's the case, you can just
db.collectionName.findOne()
This will show one document (aka. record) in the database in a pretty format.
I had this need too, Cavachon. So I created an open source tool called Variety which does exactly this: link
Hopefully you'll find it to be useful. Let me know if you have questions, or any issues using it.
Good luck!
AFAIK, there isn't a way and it is logical for it to be so.
MongoDB being schema-less allows a single collection to have a documents with different fields. So there can't really be a description of a collection, like the description of a table in the relational databases.
Though this is the case, most applications do maintain a schema for their collections and as said by Chris this is enforced by your application.
As such you wouldn't have to worry about first fetching the available keys to make a query. You can just ask MongoDB for any set of keys (i.e the projection part of the query) or query on any set of keys. In both cases if the keys specified exist on a document they are used, otherwise they aren't. You will not get any error.
For instance (On the mongo shell) :
If this is a sample document in your people collection and all documents follow the same schema:
{
name : "My Name"
place : "My Place"
city : "My City"
}
The following are perfectly valid queries :
These two will return the above document :
db.people.find({name : "My Name"})
db.people.find({name : "My Name"}, {name : 1, place :1})
This will not return anything, but will not raise an error either :
db.people.find({first_name : "My Name"})
This will match the above document, but you will have only the default "_id" property on the returned document.
db.people.find({name : "My Name"}, {first_name : 1, location :1})
print('\n--->', Object.getOwnPropertyNames(db.users.findOne())
.toString()
.replace(/,/g, '\n---> ') + '\n');
---> _id
---> firstName
---> lastName
---> email
---> password
---> terms
---> confirmed
---> userAgent
---> createdAt
This is an incomplete solution because it doesn't give you the exact types, but useful for a quick view.
const doc = db.collectionName.findOne();
for (x in doc) {
print(`${x}: ${typeof doc[x]}`)
};
If you're OK with running a Map / Reduce, you can gather all of the possible document fields.
Start with this post.
The only problem here is that you're running a Map / Reduce on which can be resource intensive. Instead, as others have suggested, you'll want to look at the code that writes the actual data.
Just because the database doesn't have a schema doesn't mean that there is no schema. Generally speaking the schema information will be in the code.
I wrote a small mongo shell script that may help you.
https://gist.github.com/hkasera/9386709
Let me know if it helps.
You can use a UI tool mongo compass for mongoDb. This shows all the fields in that collection and also shows the variation of data in it.
If you are using NodeJS and want to get the all the field names using the API request, this code works for me-
let arrayResult = [];
db.findOne().exec(function (err, docs)){
if(err)
//show error
const JSONobj = JSON.parse(JSON.stringify(docs));
for(let key in JSONobj) {
arrayResult.push(key);
}
return callback(null, arrayResult);
}
The arrayResult will give you entire field/ column names
Output-
[
"_id",
"emp_id",
"emp_type",
"emp_status",
"emp_payment"
]
Hope this works for you!
Consider you have collection called people and you want to find the fields and it's data-types. you can use below query
function printSchema(obj) {
for (var key in obj) {
print( key, typeof obj[key]) ;
}
};
var obj = db.people.findOne();
printSchema(obj)
The result of this query will be like below,
you can use Object.keys like in JavaScript
Object.keys(db.movies.findOne())

References vs embeds in MongoDB

I'm trying to figure out how to best use MongoDB for a very small and simple use case, but finding the docs somewhat confusing.
My document should represent the fact that a user can have many emails. If I follow the documentation the most obvious and simple solution is to use embeds. The problem is when I want to validate the email address for uniqueness, which is AFAIK impossible with embeds (of course I can use map/reduce, but it seems a very poor choice).
I definitely feel like emails don't deserve their own collection, but apparently embedded object doesn't let me do the validation (and if it does, I really don't believe it's going to be efficient).
How would you design the schema in this situation ?
You can define an index on the email sub-field with { unique: true } set. This will prevent multiple copies of the email address from being stored in the collection.
For example, let's say your documents look something like this:
db.users.findOne() =>
{
"name" : "xxxx",
"emails" : [
{ address: "one#domain.com", validated: false },
{ address: "two#domain.com", validated: true }
]
}
You can define a unique index on the email.address field like this:
db.users.ensureIndex(['emails.address',1], {unique: true})
Now you will get an error if you try to insert the same email address twice. It will also help you optimize looking up users by their email address which is bound to be useful in your app at some point or another.

Mongo: Would you store username or reference to username inside second collection?

Let's take a simple example, a blog post. I would store comments to a particular post within the same document.
messages = { '_id' : ObjectId("4cc179886c0d49bf9424fc74"),
'title' : 'Hello world',
'comments' : [ { 'user_id' : ObjectId("4cc179886c0d49bf9424fc74"),
'comment' : 'hello to you too!'},
{ 'user_id' : ObjectId("4cc1a1830a96c68cc67ef14d"),
'comment' : 'test!!!'},
]
}
The question is, would it make sense to store the username instead of the user's objectid aka primary key? There are pros/cons to both, pro being that if I display the username within the comment, I wouldn't have to run a second query. Con being if "John Doe" decides to modify his username, I would need to run a query across my entire collection to change his username within all comments/posts.
What's more efficient?
I will store the two fields. This way, you only run one query in the most common case (display the comments). Change user name is really rare so you will not have to update very often.
I will keep user_id because I don't like to use natural field like username as primary key and match on an object id must be faster.
Of course, it really depends on how much traffic you're going to get, how many comments you expect to have, etc… But it's likely that “do the simplest thing that works” is your friend here: it's simpler to store only the user_id, so do that until it doesn't work any more (eg, because you've got a post with 100,000 comments that takes 30 seconds to render), then denormalize and store the username along with the comments.