How can I pass parameters to a view using cradle (CouchDB) - node.js

Using cradle, how am I able to pass parameters to a view in CouchDB?
Update
Say I want to return documents which match other properties than _key (the default)...
// document format
{
_key,
postHeading,
postBody,
postDate
}
What if I wanted to match documents against the postHeading property... How would I go about this? What would the view look like, and how would I pass a search string to that view?
At the moment I'm doing this...
database.get("980f2ba66d5c8f9c91b9204a4d00022a", function (error, document)
{
});
I would like to access a view instead, and instead of the 40 character long auto-generated key, I'd like to pass a string, matching another property.
Something along the lines of this...
database.save("_design/posts", {
single: {
map: function (document)
{
if (document.postHeading == PARAMETER_PASSED_GOES_HERE)
emit(null, document);
}
}
});
database.view("posts/single", function (error, documents)
{
});

If you are querying a view try to pass second parameter as options object with your settings, for example:
db.view('characters/all', {descending: true}, function (err, res) {
res.forEach(function (row) {
sys.puts(row.name + " is on the " +
row.force + " side of the force.");
});
});
Also be aware of this:
Some query string parameters' values
have to be JSON-encoded.
EDIT:
As far as I know you can't create a view in CouchDB where you pass your custom parameter which will be used in map/reduce function code. You have to emit keys from your map function and based on them you can query the view with parameters like startkey and endkey. Try to look at Database Queries the CouchDB Way article.

db.get('vader', function (err, doc) {
doc.name; // 'Darth Vader'
assert.equal(doc.force, 'dark');
});
It looks like the searched value (parameter) here is 'dark' out of all force keys?
Cradle is also able to fetch multiple
documents if you have a list of ids,
just pass an array to get:
db.get(['luke', 'vader'], function
(err, doc) { ... });

Related

Loopback Find then update attribute or delete by id

Been trying to find samples usage for some of the static methods for a persistedModel in Loopback.
https://apidocs.strongloop.com/loopback/#persistedmodel-prototype-updateattribute
it just says:
persistedModel.updateAttributes(data, callback)
But how you I choose the which record I want to update? this is not working for me.
var order = Order.setId('whateverrecordId');
order.updateAttributes({name:'new name'},callback)
Loving loopback.. but their doc, sucks.. :(
You can use those on event listener like AfterSave
example:
Model.observe('after save', function(ctx, next) {
ctx.instance.updateAttribute(fieldname:'new value');
next();
});
1- What you did was right but i do not advise this method it's used for instance methods and generally to update fields like date for all the collection that you have so you don't need an id for it.
But you can try to make an array containing data to update containing also the ids and then make a comparison to fill in data for the ids that you have. (in #dosomething)
order.find().then(function(orders) {
orders.forEach(function(element) {
order.setId(element.id);
#DoSomething
order.updateAttribute({new: data}, function(err, instance) {
console.log(instance);
})
});
})
2- You can use updateAll to update one or many attribute.
PersistedModel.updateAll([where], data, callback)
var Updates = [{id : 1, name: name1}, ...]
Updates.forEach(function(element) {
order.updateAll({id : element.id}, {name :element.name}, function(err, count) {
if (err) {
console.error(err);
}
console.log(count); // number of data updated
})
})

Mongodb can't use parameter as update field filter key? [duplicate]

This question already has answers here:
Add a property to a JavaScript object using a variable as the name? [duplicate]
(14 answers)
Closed 5 years ago.
I want build a simple function which can update (upsert) a document by collection name, field key, field value, updateData
example:
function updateDB(tableName, id, rowInfo, checkfield, callback) {
db.collection(tableName, function (err, collection) {
if (err) {
console.log(err);
} else {
console.log(checkfield);
collection.update({ checkfield: id }, rowInfo, { upsert: true }, function (err, objects) {
if (err) {
throw err;
callback(false);
} else {
// console.log(objects);
callback(true);
}
});
}
});}
However when I use parameter as field filter in update query it always inserts new data an does not update the document. Example:
collection.update({ checkfield: id }.....
But when I change the field filter to realFieldName it works correctly. Example:
collection.update({ 'realFieldName': id }....
What is the difference between the two?
you should code it like:
var filter = {};
filter[checkfield] = id;
collection.update(filter, ...);
define an object like { checkfield: id }, checkfield is regarded as an identifier NOT a variable.
for details, please refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
An object property name can be any valid JavaScript string, or
anything that can be converted to a string, including the empty
string. However, any property name that is not a valid JavaScript
identifier (for example, a property name that has a space or a hyphen,
or that starts with a number) can only be accessed using the square
bracket notation. This notation is also very useful when property
names are to be dynamically determined (when the property name is not
determined until runtime)

Is there a way to know if there are more documents available for pagination in MongoDB?

I am writing a Node.JS app with MongoDB. One of the things I need to implement is the listing of the objects. I've already implemented the pagination using the skip() and limit() functions, thanks to this answer:
myModel.find()
.skip(offset)
.limit(limit)
.exec(function (err, doc) {
// do something with objects
})
The thing is, I want my endpoint to return metadata, and one of the fields I need is a boolean representing if there are more objects that can be loaded.
The most simple way to implement this is just loading one more object (to determine if there are more objects to display) and not showing it to the user, something like that:
myModel.find()
.skip(offset)
.limit(limit + 1)
.exec(function (err, doc) {
var moreAvailable; // are there more documents?
if (doc.length > limit) {
moreAvailable = true;
doc.length = limit; // don't show the last object to the user
} else {
moreAvailable = false;
}
})
But I'm pretty sure that there should be more clever way to do this. Is it?
Use db.collection.find(<query>).count() https://docs.mongodb.com/manual/reference/method/cursor.count/
var total = db.collection.find(<query>).count();
var is_more = total > skip + limit;

how to improve the view with map/reduce in couchdb and nodejs

I'm using nodejs with the module cradle to interact with the couchdb server, the question is to let me understanding the reduce process to improve the view query...
For example, I should get the user data from his ID with a view like this:
map: function (doc) { emit(null, doc); }
And in node.js (with cradle):
db.view('users/getUserByID', function (err, resp) {
var found = false;
resp.forEach(function (key, row, id) {
if (id == userID) {
found = true;
userData = row;
}
});
if (found) {
//good, works
}
});
As you can see, this is really bad for large amount of documents (users in the database), so I need to improve this view with a reduce but I don't know how because I don't understand of reduce works.. thank you
First of all, you're doing views wrong. View are indexes at first place and you shouldn't use them for full-scan operations - that's ineffective and wrong. Use power of Btree index with key, startkey and endkey query parameters and emit field you like to search for as key value.
In second, your example could be easily transformed to:
db.get(userID, function(err, body) {
if (!err) {
// found!
}
});
Since in your loop you're checking row's document id with your userID value. There is no need for that loop - you may request document by his ID directly.
In third, if your userID value isn't matches document's ID, your view should be:
function (doc) { emit(doc.userID, null); }
and your code will be looks like:
db.view('users/getUserByID', {key: userID}, function (err, resp) {
if (!err) {
// found!
}
});
Simple. Effective. Fast. If you need matched doc, use include_docs: true query parameter to fetch it.

MongoDB Async - Find or create docs; return array of them

This is likely a simple answer but I'm relatively new to asynchronous programming and I'm looking for somebody to point me in the right direction.
My question is this - What is the best way to go about finding or creating a number of documents from an array of names (I'm using Mongoose) and then returning an array of _id's?
So to be clear, I want to:
Given an array of names, find or create a document with each name
Return an array of the existing or newly created documents _ids
You can use async module and within it it's async.parallel() method -
https://github.com/caolan/async#quick-examples
async.parallel([
function(){ ... },
function(){ ... }
], callback);
Or you can use promises and then Q.all() to get the array of ids back -
https://github.com/kriskowal/q#combination
Q.all(arrayOfFindOps).then(function(rows) {
return _.pluck(rows, '_id')
}
If you don't want to use any of the above and do it with callbacks, then you have to keep track of the count of array length, keep adding the ids to an array and when your completion counter reaches array length, call another function with the array you made.
This code can be easily modified to meet your requirements. Call this function for each document that required to be created if doesn't exist.
function(req, reply) {
// return document. if not found, create docuemnt.
docModel.findOne( {'name': req.params.name}, function ( err , doc) {
if(err){
//handle error
}
if(doc===null){
//find failed, time to create.
doc = new docModel( {'name': req.params.name} );
doc.save(function(err){
if(err){
//handle error
}
});
}
return reply(user._id);
});
}

Resources