Couchdb views generation - couchdb

I am learning couchdb, so I have a very basic questions. Suppose I have a couch database called email where documents look like:
{
"_id": "fe7759fdf36t",
"status": "sent",
"sent_at": 1357151443,
}
{
"_id": "ewrwe4a38d2353",
"status": "failed",
"sent_at": 2347151421,
}
{
"_id": "f4559fjffd2353",
"status": "sent",
"sent_at": 11715154,
}
I want to create two views
1) Retrieve all documents where status = sent
2) Retrieve all documents where status = failed and sent_at > 11715157
3) Retrieve all documents sorted by sent_at descending/ascending and status = sent
For (1), I wrote,
{
"_id": "_design/sentdoc",
"_rev": "2-dd88de7196c06eed41d2d83a958f0388",
"views": {
"query": {
"map": "function(doc) { if(doc.status == 'sent') {emit(doc_id, doc);} }"
}
}
}
I guess I am doing something wrong there, so it is not working. Can anyone suggest how to write all these three views?

Create a view like this
function(doc){
emit([doc.status, doc.sent_at], doc);
}
Query #1
Try these params in your curl statement (or Ruby library or whatever)
startkey = ["sent"]
endkey = ["sent",{}]
Query #2
startkey = ["failed", 11715157]
endkey = ["failed", {}]
Query #3
startkey = ["sent"]
endkey = ["sent", {}]
descending = true
I've not tested this, but should point you in the right direction.

Related

CouchDB/PouchDB design documents query with startkey endkey not working

In my database I have (not only) two types of documents in a one-to-many relationship. I tried to manage this like the following example shows:
{
_id : "class:xyz"
type: "class"
... other keys ...
}
{
_id : "class:xyz:pupil:abc"
type: "pupil"
... other keys ...
}
If I query my docs with allDocs() like
http://url_of_my_server:5984/my_database/_all_docs?include_docs=true&?startkey="class:xyz:pupil:"&endkey="class:xyz:pupil:\ufff0"
I get all docs of type pupil related to the mentioned doc of type class like wanted.
For performance I had the idea to introduce a design document to query only the docs of type pupil and not all docs every time:
{
"_id": "_design/types",
"language": "javascript",
"views": {
"classes": {
"map": "function(doc){ if(doc.type == \"class\"){emit(doc.id, doc);} }"
},
"pupils": {
"map": "function(doc){ if(doc.type == \"pupil\"){emit(doc.id, doc);} }"
},
}
}
But if I query with this design document like
http://url_of_my_server:5984/my_database/_design/types/_view/pupils?include_docs=true&?startkey="class:xyz:pupil:"&endkey="class:xyz:pupil:\ufff0"
I get no result (only an empty array/no rows).
Where is my mistake or what is wrong in my conception? I actually have no idea? Thanks in advance for your advice.
First, for a view never emit the document as a value; it is quite redundant since one may use include_docs=true - and worse, it consumes storage unnecessarily.
Assuming two documents
{
_id : "class:xyz:pupil:abc"
type: "pupil"
},
{
_id : "class:xyz:pupil:xyz"
type: "pupil"
}
And the map function for pupils
"pupils": {
"map": "function(doc){ if(doc.type == \"pupil\"){emit(doc.id, doc);} }"
}
The view index for pupils looks like this
id
key
value
class:xyz:pupil:abc
null
{"_id": "class:xyz:pupil:abc", /* etc */ }
class:xyz:pupil:xyz
null
{"_id": "class:xyz:pupil:xyz", /* etc */ }
So the key columns are null because the map function is emitting doc.id as the key.
See it? doc.id is undefined - emit(doc._id) instead.
Fix the design document map functions (including not emitting doc as value)
{
"_id": "_design/types",
"views": {
"classes": {
"map": "function(doc){ if(doc.type == \"class\"){emit(doc._id);} }"
},
"pupils": {
"map": "function(doc){ if(doc.type == \"pupil\"){emit(doc._id);} }"
}
}
}
Given the two hypothetical documents, the pupils index now looks like this
id
key
value
class:xyz:pupil:abc
class:xyz:pupil:abc
null
class:xyz:pupil:xyz
class:xyz:pupil:abc
null
Now that the view index's key has a value the query will operate as intended.
I highly recommend using Fauxton as it provides a quick means to view an index among other things.

How to do query by example on ONLY ONE nested attributes?

So I'm using ArangoDB and got a nested data structure like the following:
doc 1 = { "a" : {
"uid": 1,
"properties":{
"meta": 0
}
}
}
doc 2 = { "a" : {
"uid": 1,
"properties":{}
}
}
I want to be able to fetch all document where uid is 1 without having to take in account the properties attribute's value.
Doing a fetch by example with { "a" : { "uid": 1 } } return nothing.
Assuming doc1 and doc2 are documents saved in a document collection docs, you can access all documents with uid=1 by filtering on the subattribute a.uid.
AQL example:
FOR doc IN docs FILTER doc.a.uid==1 RETURN doc

Finding Overlap date ranges between startdate and enddate in couch Db or cloudant

Hello I am building a reservation app using database as couchDb. I have several reservation documents and each of them has roomId, start date and end date.
Now when user creates a meeting request with roomId, start date and end date, I need to search for overlaps time ranges between the start time and endtime in the existing reservations and create a reservations only when there is no conflict. Along with this I also need to check for roomid.
The requirement is similar to Determine Whether Two Date Ranges Overlap.
I had created a view on my couch db emitting three keys:
function (doc) {
if (doc.type == "reservation") {
emit([doc.roomid, doc.startTime, doc.endTime], doc);
}
}
I did try creating something like
?startkey=["1970-01-01T00:00:00Z", ""]&endkey=["\ufff0", "1971-01-01T00:00:00Z"]
However I am not really getting how to compound query the view to find range of date along with the roomid.
Any help would be appreciated.
You could use Cloudant Query and specify the (StartA <= EndB) and (EndA >= StartB) search condition that's outlined in the referenced answer.
Create an index
Send a POST request to the _index endpoint, passing the following JSON data structure as payload.
POST https://$USERNAME:$PASSWORD#$HOST/$DATABASE/_index HTTP/1.1
{
"index": {
"fields": [
{ "name":"startTime",
"type":"string"
},
{
"name":"endTime",
"type":"string"
},
{
"name":"roomid",
"type":"string"
}
]
},
"type": "text"
}
Query the index
Send a POST request to the _find endpoint, passing the following JSON data structure as payload.
POST https://$USERNAME:$PASSWORD#$HOST/$DATABASE/_find HTTP/1.1
{
"selector": {
"startTime": {
"$lte": "2017-03-06T15:00:00Z"
},
"endTime": {
"$gte": "2017-03-06T14:00:00Z"
},
"roomid": {
"$eq": "room 123"
}
}
}
Replace the timestamp and room identifier values as needed. If the query returns at least one document you've encountered a booking conflict.

Editing/Updating nested objects in documents CouchDB (node.js)

I'm trying to add (aka. push to existing array) in couchDB document.
Any feedback is greatly appreciated.
I have a document called "survey" inside my database called "database1".
I have "surveys" as a set of arrays which consists of objects that has information on each survey.
My goal is to update my "survey" document. Not replacing my array, but adding a new object to the existing array. I've used "nano-couchdb" and "node-couchdb", but could not find a way around it. I was able to update my "surveys", but it would replace the whole thing, not keeping the existing objects in array.
1) Using Nano-couchdb:
db.insert({ _id, name }, "survey", function (error, resp) {
if(!error) { console.log("it worked")
} else {
console.log("sad panda")}
})
2) Using couchdb-node:
couch.update("database1", {
_id: "survey",
_rev:"2-29b3a6b2c3a032ed7d02261d9913737f",
surveys: { _id: name name: name }
)
These work well with adding new documents to a database, but doesn't work with adding stuff to existing documents.
{
"_id": "survey",
"_rev": "2-29b3a6b2c3a032ed7d02261d9913737f",
"surveys": [
{
"_id": "1",
"name": "Chris"
},
{
"_id": "2",
"name": "Bob"
},
{
"_id": "1",
"name": "Nick"
}
]
}
I want my request to work as it would for
"surveys.push({_id:"4",name:"harris"})
whenever new data comes in to this document.
Your data model should be improved. In CouchDB it doesn't make much sense to create a huge "surveys" document, but instead store each survey as a separate document. If you need all surveys, just create a view for this. If you use CouchDB 2.0, you can also query for survey documents via Mango.
Your documents could look like this:
{
"_id": "survey.1",
"type": "survey",
"name": "Chris"
}
And your map function would look like that:
function (doc) {
if (doc.type === 'survey') emit(doc._id);
}
Assuming you saved this view as 'surveys' in the design doc '_design/documentLists', you can query it via http://localhost:5984/database1/_design/documentLists/_view/surveys.

Node, MongoDB (mongoose) distinct count

I have a collection with multiple documents and every one of them has and 'eID' field that is not unique. I want to get the count for all the distinct 'eID'.
Example: if there are 5 documents with the 'eID' = ObjectID(123) and 2 documents with 'eID' = ObjectID(321) I want to output something like:
{
ObjectID(123): 5,
ObjectID(321): 2
}
I don't know if that can be done in the same query but after knowing what are the most ocurring eID's I want to fetch the referenced documents using the ObjectID
Mongoose version 3.8.8
$status is the specific field of collection that i need to count distinct number of element.
var agg = [
{$group: {
_id: "$status",
total: {$sum: 1}
}}
];
model.Site.aggregate(agg, function(err, logs){
if (err) { return res.json(err); }
return res.json(logs);
});
//output
[
{
"_id": "plan",
"total": 3
},
{
"_id": "complete",
"total": 4
},
{
"_id": "hault",
"total": 2
},
{
"_id": "incomplete",
"total": 4
}
]
This answer is not in terms of how this query can be written via mongoose, but I am familiar with the nodejs MongoClient class if you have further questions regarding implementation.
The best (most optimal) way I can think of doing this is to use mapReduce or aggregation on your database. The closest thing to a single command would be the distinct command, which can be invoked on collections, but this will only give you an array of distinct values for the eID key.
See here: http://docs.mongodb.org/manual/core/map-reduce/
For your specific problem, you will want your map and reduce functions roughly as follows:
var map = function() {
var value = 1;
emit(this.eID, value);
};
var reduce = function(key, values) {
var result = 0;
for(var i=-1;++i<values.length;){
var value = values[i];
result += value;
};
return result;
};
There might be an easier way to do this using the aggregation pipeline (I would post the link but I don't have enough reputation).
I also found the mapReduce command for mongoose: http://mongoosejs.com/docs/api.html#model_Model.mapReduce

Resources