Pass arguments in couchdb-nano view function - node.js

I am using nodejs's nano npm module and couchdb to get the total number of documents based on a status message that I should be able to pass in a couchdb view.
The view looks like the following.
{
_id: "_design/docCount",
views: {
fileCountByStatus: {
reduce: "_count",
map:
'function (doc) {\n if(doc.status === "COMPLETE") {\n emit(doc._id, 1);\n }\n}'
},
},
language: "javascript"
}
I am accessing the above view using nano's view function.
My question is, is there anyway I can pass the doc status using the view function instead of hardcoding it (COMPLETE in the above case)

Answering my own question.
The general case is to create an index on status with a map function like this:
function(doc) {
emit(doc.status, 1)
}
Then you can query the view for any value of status
db.view('mydesigndoc', 'myview', { key: 'complete' })
// or
db.view('mydesigndoc', 'myview', { key: 'new' })

Related

This view works in PouchDB but why does it fail to sync with CouchDB?

After some time developing an app with PouchDB I am now beginning my first attempts at syncing with a remote CouchDB instance. For now I am only syncing with the CouchDB provided by the installable OSX CouchDB app.
Documents appear to sync fine but I am having trouble with a particular view. I've checked it is valid JS and can't see an error.
I am storing each view in its own design document, which I read is a best practise.
So far I've tried:
Removing toLowerCase() (no reason really, just to check)
Moving the value emitted into its own variable
Other folk have had issues with view sync due to the use of modern JS features but I believe I've written mine with ES5, which I've read is what is required.
Here is the view definition code:
const ddoc = {
_id: '_design/title-only',
views: {
'title-only': {
map: function titleOnly(doc) {
if (doc.type && doc.type === 'song' && doc.title) {
emit(doc.title.toLowerCase(), {
id: doc._id,
title: doc.title,
authors: doc.authors,
starred: doc.starred || false,
labels: doc.labels || [],
createdAt: doc.createdAt,
});
}
}.toString(),
},
}
};
I get an error of type "compilation_error".
Here is the error message:
"Compilation of the map function in the 'title-only' view failed: Expression does not eval to a function. (function titleOnly(doc) {
if (doc.type && doc.type === 'song' && doc.title) {
emit(doc.title.toLowerCase(), {
id: doc._id,
title: doc.title,
authors: doc.authors,
starred: doc.starred || false,
labels: doc.labels || [],
createdAt: doc.createdAt,
});
}
})"
Any pointers gratefully received, thanks.
Don't use a named function.
In other words, replace this:
map: function titleOnly(doc) {
with this:
map: function(doc) {

error in filtered function creation on couchdb

I'm trying to follow this tutorial to filter the replication between a pouchdb and a couchdb databases
https://pouchdb.com/2015/04/05/filtered-replication.html
The problem is when I try to create the filtered function in the Fauxton webapp. In my created database, I click Design Document > New Docs and then paste the function:
{
"_id": "_design/app",
"filters": {
"by_agent": function(doc, req) {
return doc.agent === req.query.agent;
}.toString()
}
}
and when I click Create Document button, it crashes. The javascript console says
Uncaught SyntaxError: Unexpected token u in JSON at position 61
at JSON.parse ()
at t.checkDocIsValid (https://127.0.0.1:6984/_utils/dashboard.assets/js/bundle-b8e0ba71119195edb7ec64b98f53d9b9.js:529:19481)
at t.saveDoc (https://127.0.0.1:6984/_utils/dashboard.assets/js/bundle-b8e0ba71119195edb7ec64b98f53d9b9.js:529:19056)
...
how do I create the filtered function in couchDB? Maybe that isn't the procedure or I have to create it on another dababase. Thanks in advance
So what you're trying to do is use JavaScript code to create a view. Therefore, Fauxton takes only JSON as a document.
Here's how you can get the JSON from the JavaScript snippet :
//The snippet you had was a JavaScript object
//Even if it seems like a JSON object, there is a function() declaration followed by a .toString()
//By doing so, it easier to write functions instead of writing them in a raw string.
var javascriptObject = {
"_id": "_design/app",
"filters": {
"by_agent": function(doc, req) {
return doc.agent === req.query.agent;
}.toString()
}
}
console.info("You should use the following string in your Fauxton Editor:");
console.log(JSON.stringify(javascriptObject));
You should use the following string instead of the JavaScript snippet you tried:
{
"_id": "_design/app",
"filters": {
"by_agent": "function (doc, req) {\n return doc.agent === req.query.agent;\n }"
}
}

Mongojs attempting to push to array

I'm trying to keep a list of all the sites I'm working on right now, and I'm having issues using $push.
I've created a document with this:
accountData = {
'accountid': account_id,
sites: {
'001': 'example.com',
}
};
db.accounts.insert(accountData);
This works great, I get:
{ accountid: 'AC654164545', 'sites.001': { '$exists': true } }
And I would like to add to the sites object. This is what I'm trying:
db.accounts.update(
{'accountid': account_id},
{
$push:
{
sites:
{
'002': 'example2.com'
}
}
},
function(err,doc){
console.log(err);
}
);
The error that I get is:
err: 'The field \'sites\' must be an array but is of type Object in document
I don't want the document to be created with an array, as I know that if I did something like this when inserting:
sites: {
'002': 'example2.com',
'003': 'example3.com',
'004': 'example4.com',
}
It would work just fine.
How do I use $push, or any other command, to add to the "sites" object without it being an array?
It can't be an array because I'm using the following to search for existing sites.
search['sites.' + site_id] = { $exists : true };
Ok, I figured out what the problem was.
I wasn't thinking about the problem in the right context.
The error was correct in saying it needed to be an array, so I changed the "sites" object into an array like this when created (initial insert), so it's an array:
accountData = {
'accountid': account_id,
sites: [{'001': 'example.com'}]
};
Then, by using the exact same code above to $push, it worked properly.

NodeJS + Mongo native – check if collection exists before query

I've got a function, trying to get a specific value from settings collection in MongoDB. The marker for settings object, containing settings values, in settings collection is {'settings':'settings'}. The schema is:
collection:setting
|--object
|--{'settings':'settings'}
|--{'valueA':'valueA'}
|--...
The problem is when I first time query settings object, the collection 'settings' simply does not exists. So,
exports.getInstruments = function (callback) {
db.collection("settings", function(error, settings) {
settings.find({ "settings" : "settings" }), (function(err, doc) {
callback(doc.instruments);
});
]);
}
just hangs and callback is not invoked. If collection does not exist, I should return "" or undefined, else - doc.instrumens.
There's an exists() function that you could use to determine whether or not to execute the code that hangs.
> db.getCollection('hello').exists()
null
> db.getCollection('world').exists()
{ "name" : "testdb.world" }
You could potentially take advantage of db.createCollection which explicitly creates a collection:
> db.createCollection("asd")
{ "ok" : 1 }
> db.createCollection("asd")
{ "errmsg" : "collection already exists", "ok" : 0 }
Just check if the command succeeded based on the ok field.
You shouldn't need to specially handle the new collection case, I think the problem is with your code.
Aside from some syntax problems, the main problem is that find passes a Cursor to your callback function, not the first matching document. If you're expecting just one doc, you should use findOne instead.
This should work:
exports.getInstruments = function (callback) {
db.collection("settings", function(error, settings) {
settings.findOne({ "settings" : "settings" }, function(err, doc) {
callback(doc && doc.instruments);
});
});
};

MongoDB Upsert add to array

I'm trying to insert/update an array of strings in a mongodb document using some typescript code running in NodeJS.
The following code is typescript but I guess JS developers will get it w/o any problems:
export function addEvents(entityId: string,
events: string[] ,
callback: () => void) {
db.collection('events', function(error, eventCollection) {
if(error) {
console.error(error); return;
}
eventCollection.update({ _id: entityId }, { "$pushAll ":
{ events: events }},
function(error, result) {
if(error) {
console.error(error); return;
}
callback();
});
});
}
the document have the following structure:
{
_id : string
events : ["array","of","strings"]
}
I simply want to append an array strings at the end of the existing array for a specific _id.
I don't quite get if I should use update,save, $push ,$pushall etc.
Can someone explain?
If I understood correctly the problem is that pushAll does nothing or update returns error? Maybe copy-paste mistake in your example but I think you have typo here.
{ "$pushAll ": { events: events }}
It should be
{ $pushAll: { events: events }}
Your combination of update and $pushAll looks like the best choice for what you're doing here -- it's for appending an array to an existing array. $push is for adding an element to an array. save would involve getting the existing events array, appending to it, then saving the document.
The extra space in "$pushAll " needs to be removed. It may have quotes: "$pushAll".
Found the problem, I needed to pass "{ upsert = true }" as a third argument to the update function.
To achieve 'upsert' semantics in this case, you'd need to use $addToSet. If you have an array of values to add, you'd need to throw in the $each modifier. From mongo shell:
db.events.update(
{ _id: entityId },
{ $addToSet: { $each: events } }
)

Resources