couchdb, get last 10 documents - couchdb

Using mysql this would be:
SELECT * FROM thetable ORDER BY id DESC LIMIT 10
How can I do this in couchdb for all documents with "type":"message"? (without pulling all documents with type:message)
Thanks

Create a view that emits all doc ids. The view keys will be used for sorting automatically.
function(doc) {
if(doc.type && doc.type === 'message'){
emit(doc._id, null);
}
}
Then execute a query: http://host/yourdb/_design/yourdesigndoc/_view/viewname?limit=10&include_docs=true&descending=true
Because you want the full document, we didn't included anything as value in the view. Instead, we add include_docs=true to fetch every full document for the view entries.
Note that there is also a builtin view that does the same: http://host/yourdb/_all_docs?limit=10&include_docs=true&descending=true
PS: You should be aware of the fact that CouchDB by default uses UUIDs as IDs, which will render the sorting more or less useless, if you really want to get the latest docs. Either provide your own incremental IDs (what about distribution/replication?) or use a new field that stores the time the doc has been created and use in the view as well.
If your docs have a created field (i.e. UNIX timestamp, JavaScript Date.now() or even a RFC 3339-like string), you can build an index on these values.
Here is the time-based view:
function(doc) {
if(doc.type && doc.type === 'message' && doc.created){
emit(doc.created, null);
}
}
Note that we will not emit the doc._id itself. However, CouchDB stores the doc._id where the data came from for each emitted key/value pair automatically, so we can again use include_docs=true to fetch the complete docs.
Query http://host/yourdb/_design/yourdesigndoc/_view/viewname?limit=10&include_docs=true&descending=true

If the IDs of your documents are already incremental, instead of the default UUIDs of CouchDB, you do not even need to define a view, you can just use the default _all_docs view, e.g.
http://couchdb_host/your_db/_all_docs?limit=10&descending=true&include_docs=true

Related

How can I get another document in a design document function?

There are some special design document functions, like updates and validate_doc_update besides of views and lists functions; where our functions are get executed upon specific events by issuing a single document per call.
I wonder if we can fetch another document within a single update function, like so:
updates: {
"hello" : "function(doc, req) {
if (doc.type === 'example') {
otherDoc = fetch(doc.relatedDocId)
doc.relatedDocName = otherDoc.name
return [doc, 'Hey Hey...']
}
}"
Point is I want to use a fetch(documentId) like function in order to update some other documents based on current document information.
When a document is updated, there is no way in CouchDB to automatically update a second, related document. You may want to implement a worker listening to the changes feed and perform such updates there.

Can I create multiple collections per database?

Switching from mongo to pouchdb (with Cloudant), i like the "one database per user" concept, but is there a way to create multiple collections/tables per database ?
Example
- Peter
- History
- Settings
- Friends
- John
- History
- Settings
- Friends
etc...
Couchdb does not have the concept of collections. However, you can achieve similar results using type identifiers on your documents in conjunction with Couchdb views.
Type Identifiers
When you save a document in Couchdb add a field that specifies the type. For example, you would store a friend like so:
{
_id: "XXXX",
type: "Friend",
first_name: "John",
...
}
And you would store history like this:
{
_id: "XXXX",
type: "History",
url: "http://www.google.com",
...
}
Both of these documents would be in the same database, and if you queried all documents on that database then you would receive both.
Views
You can create views that filter on type and then query those views directly. For example, create a view to retrieve friends like so (in Cloudant you can go to add new Design Document and you can copy and paste this directly):
{
"_id" : "_design/friends",
"views" : {
"all" : {
"map" : "function(doc){ if (doc.type && doc.type == 'Friend') { emit(doc._id, doc._rev)}}"
}
}
}
Let's expand the map function:
function(doc) {
if (doc.type && doc.type == "Friend") {
emit(doc._id, doc._rev);
}
}
Essentially this map function is saying to only associate documents to this view that have type == "Friend". Now, we can query this view and only friends will be returned:
http://SERVER/DATABASE/_design/friends/_view/all
Where friends = name of the design document and all = name of the view. Replace SERVER with your server and DATABASE with your database name.
You can find more information about views here:
https://wiki.apache.org/couchdb/Introduction_to_CouchDB_views
You could look into relational-pouch for something like this. Else you could do "3 databases per user." ;)
I may not fully understand what you need here but in general you can achieve what you describe in 3 different ways in CouchDB/Cloudant/PouchDB.
Single document per person (Peter, John). Sure - if the collections are not enormous and more importantly if they are not updated by different users concurrently (or worse in different database instances) leading to conflicts then, in JSON just an element for each collection, holding an array and you can manipulate everything with just one document. Makes access a breeze.
Single document per collection (Peter History, Peter Settings ect). Similar constraints, but you could create a document to hold each of these collections. Provided they will not be concurrently modified often, you would then have a document for Peter's History, and another for Peter's Settings.
Single document per item. This is the finest grain approach - lots of small simple documents each containing one element (say a single History entry for Peter). The code gets slightly simpler because removing items becomes a delete and many clients can update items simultaneously, but now you depend on Views to bring all the items into a list. A view with keys [person, listName, item] for example would let you access what you want.
Generally your data schema decisions come down to concurrency. You mention PouchDB so it may be that you have a single threaded client and option 1 is nice and easy?

Use linux timestamp in CouchDB map function

Trying to update an existing CouchDB map function so that it only returns docs created in the past 24 hours.
The current map is very simple
function(doc) {
if(doc.email && doc.type == 'user')
emit(doc.email, doc);
}
I'd like to get the current linux timestamp value and compare that to the creationTime.unix value stored in the doc.
Is that possible?
N.B I'm building the view in futon
I do not know if you can do that, but it if you can that would be very bad for CouchDB database sanity.
Map functions for same document should always emit same values, each time you invoke it (provided that document has not changed in the mean time). This is important since CouchDB stores this emited data in the index, and does not recalculate it again until it is necessary. If map functions could emit different values for the same doc, that would render index unusable.
So, no, do not try that.
Good news is that you can easily achieve what you need without that. If you emit creation time, than you can query your view just for docs with creation time in certain interval like in:
/blog/_design/docs/_view/by_date?startkey="2010/01/01 00:00:00"&endkey="2010/02/00 00:00:00"
Read more how you can query your views in CouchDB The Definitive Guide

CouchDB set-difference/not-in condition

I prepare to use CouchDB to my project. but cannot find a way to implement a view like an SQL SELECT * FROM Employees WHERE LastName NOT IN (SELECT LastName FROM Managers). In other words, I want to get a set from view A but not in view B. Question: how to implement not-in condition in CouchDB?
Keeping employees and managers lists different sets of documents is using relational structure where you DB is not relational. If, for some reason, you are forced to do that, you need some way to distinguish the scheme of the doc (from which table it is). Lets say you are doing it with field scheme:
{ _id: "EMPL_ID", scheme: "employee", ... }
{ _id: "MNGR_ID", scheme: "manager", employee: "EMPL_ID", ... }
Then you can use map:
function (doc) {
if (!doc.scheme) return;
if (doc.scheme != "manager") emit(doc.last_name, doc);
}
If, for some strange reason, you cannot do that, and you only have the reference to employee doc in manager doc, you can emit both documents:
function (doc) {
if (some_test_for_being_employee_scheme(doc))
emit([doc._id, 1], doc);
if (doc.emp_id)
emit([doc.emp_id, 0], null);
}
You will get the list of employees with keys ["employee_id", 1], and each manager is preceded with the row labeled as manager (key [..., 0]). This will require some space, but with list function you can filter out managers easily and the client will receive from DB only the non-managers.
Keep in mind, that it is only the workaround for not making proper DB design.
If you change the model to make it fit a document-oriented database, this would be easy. I generally keep a "type" key in all of my documents to keep different types of documents straight. If you have a single "person" type and decorate all "person" documents who are also "manager" with a separate key, you could easily emit view keys only for non-managerial personnel. If you opt to have a separate "manager" type, you could similarly restrict emitted view keys to non-managers only.
I think the answer is simply: you can't mix view results. Views are independent.
However, there is a strategy called view collation that probably solves your problems. I suggest reading this: http://wiki.apache.org/couchdb/View_collation
To summarize it: You need to use different document types and then use a single view to collate the results.

Does CouchDB supports referential integrity?

I am new to CouchDB and learning about it. I did not come across CouchDB support for referential integrity.
Can we create a foreign key for a field in the CouchDB document?
For e.g. Is it possible to ensure a vendor name used in a order document is available in the vendor database?
Does CouchDB support referential integrity?
And Is it possible to make a field in a document as Primary key?
No, CouchDB doesn't do foreign keys as such, so you can't have it handle the referential integrity of the system for you. You would need to handle checking for vendors in the application level.
As to whether you can make a field a primary key, the primary key is the _id field, but you can use any valid json as a key for the views on the db. So, for instance you could create a view of orders with their vendor as the key.
something like
function(doc) {
if (doc.type == 'order')
emit(doc.vendor,doc);
}
would grab all the docs in the database that have a type attribute with the value order and add them to a view using their vendor as the key.
Intro to CouchDB views
These questions are incredibly relational database specific.
In CouchDB, or any other non-RDBMS, you wouldn't store your data the same way you would in an RDBMS so designing the relationship this way may not be best. But, just to give you an idea of how you could do this, lets assume you have a document for a vendor and a bunch of documents for orders that need to "relate" back to the vendor document.
There are no primary keys, documents have an _id which is a uuid. If you have a document for a vendor, and you're creating a new document for something like an order, you can reference the vendor documents _id.
{"type":"order","vendor-id":"asd7d7f6ds76f7d7s"}
To look up all orders for a particular vendor you would have a map view something like:
function(doc) { if (doc.type == 'order') {emit(doc['vendor-id'], doc)}}
The document _id will not change, so there is "integrity" there, even if you change other attributes on the vendor document like their name or billing information. If you stick the vendor name or other attributes from the vendor document directly in to the order document you would need to write a script if you ever wanted to change them in bulk.
Hope that helps a bit.
While not possible to create an FK constraint, it is possible using Couch's Validate function
function(newDoc, oldDoc, userCtx, secObj) {
if(newDoc && newDoc.type) switch(newDoc.type){
case 'fish':
var allSpecies = ['trout','goldfish'];
if(!allSpecies.contains(newDoc.species)){
throw({forbidden : 'fish must be of a know species'});
}
break;
case 'mammals':
if(!['M','F'].contains(newDoc.sex)){
throw({forbidden : 'mammals must have their sex listed'});
}
break;
}
}
Now, if a person were really clever (I'm not), they might do a call out to the DB itself for the list of Species... that would be a foreign key.
You may also want to read up on:
How do I DRY up my CouchDB views?

Resources