NodeJS V8 Pass additional argument to callback - node.js

I write an application using NodeJS, ExpressJS, MongoDB (with Mongoose)...
Everything work perfectly, but, when I have a loop for fetch records and do something with the results, like this:
for(var i = 0; i < 10; i++) {
recods.findOne({number: i}, function(err,doc){
...
});
}
The variable "i" in the scope of callback function is passed by reference and the result is not the desired.
When the callback is called the loop has already run and the variable has changed.
If I try to pass argument as anonymous function, does not work, because it replace the needed arguments:
for(var i = 0; i < 10; i++) {
records.findOne({number: i}, (function(err,doc){
...
})(i));
}
In this way, I lost the "err,doc" arguments,
What can I do to solve this big problem?

You can bind it to your callback to create a partial function with its first argument set to i:
for (var i = 0; i < 10; i++) {
records.findOne({number: i}, function(i, err, doc) {
...
}.bind(records, i));
}

You're applying an anonymous function in the wrong place. It should be applied outside of the function that uses i, not to the callback function.
for (var i = 0; i < 10; i++) {
(function(i) {
records.findOne({number: i}, function(err, doc) {
...
});
}(i));
}

While with a few simple fix-ups to capture the value of i in a closure works as shown in the other answers, you might also consider using Mongoose in a different and likely more efficient way:
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
records.find( { number : { $in : numbers } }, function(err, allDocs) {
if (err) { throw err; }
// allDocs are now available in an array (they aren't ordered)
// allDocs.length
// allDocs[0].number ...
});
Using the $in operator (reference) makes just one call to the Database, and finds all matching documents, rather than doing individual calls.

Related

Adding functions in search index of loudant

I have a Json document in cloudant as:
{
"_id": "3-f812228f45b5f4e4962505561953ew245",
"_rev": "3-f812228f45b5f4e496250556195372b2",
"wiki_page": "http://en.wikipedia.org/wiki/African_lion",
"name": "african lion",
"class": "mammal",
"diet": "herbivore"
}
I want to make a search index that can search this document when I input queries as "afrian lion" or "lion african",...
I make a function that can return all cases of permutation in "doc.name" for indexing (This function works well and it also had been checked in pure JS environment). However, it does't work in cloudant, the output return null when i input a query.
This is a code that I made in search index:
function(doc){
var list = [];
function permute(ss, used, res, level, list){
if(level==ss.length&&res!==""){
list.push(res);
return;
}
for(var i=0; i<ss.length; i++){
console.log("loops");
if (used[i]===true){
continue;
}
if(level>=0){
if (res!="" && list.indexOf(res)<0){
list.push(res.trim());
}
used[i]=true;
permute(ss, used, res+" "+ss[i], level+1, list)
used[i]=false;
}
}
}
function permuteword(s){
var ss=s.split(" ");
var used = [];
var res = "";
list = [];
permute(ss, used, res, 0, list);
console.log(list);
}
var contentIndex=[];
contentIndex=permuteword("african lion");
for(var i=0; i<contentIndex.length; i++){
index("default", contentIndex[i]);
}
}
How can i solve the problem?
Update
Your update looks good, but there is still one issue: you are not returning the list from the permuteword function. I believe you also need to remove calls to console.log. Once I did these two things I was able to get it to work with Cloudant using the following search queries (I also changed your hard-coded call with "african lion" back to doc.name):
default:"african"
default:"african lion"
default:"lion"
default:"lion african"
Here is the final script:
function(doc){
var list = [];
function permute(ss, used, res, level, list){
if(level==ss.length&&res!==""){
list.push(res);
return;
}
for(var i=0; i<ss.length; i++){
if (used[i]===true){
continue;
}
if(level>=0){
if (res!="" && list.indexOf(res)<0){
list.push(res.trim());
}
used[i]=true;
permute(ss, used, res+" "+ss[i], level+1, list)
used[i]=false;
}
}
}
function permuteword(s){
var ss=s.split(" ");
var used = [];
var res = "";
list = [];
permute(ss, used, res, 0, list);
return list;
}
if (doc.name) {
var contentIndex=permuteword(doc.name);
for(var i=0; i<contentIndex.length; i++){
index("default", contentIndex[i]);
}
}
}
Updated JSFiddle:
https://jsfiddle.net/14e7L3gw/1/
Original Answer
I believe there are issues with your Javascript. The permuteword function is not returning any results. See this JSFiddle:
https://jsfiddle.net/14e7L3gw/
Note: I added some logging and commented out the call to index. Run with your browser debugger to see the output.
Here is what is happening:
The first call to permuteword calls permute(["african","lion"], [], "", 0, []);
The first if in permuteword fails because level (0) != ss.length() (2) and res == "".
Then the function loops through ss, but never does anything because level = 0.
Ultimately permuteword returns an empty array, so nothing gets indexed.

Sequelize.js afterFind argument explanation

I'm trying to implement an afterFind hook on a model and can't quite figure out what the semantics are. I'll pulled the following together from trial and error using the doc and other StackOverflow questions as guidelines.
My goal is to massage the result (by applying get(plain : true)) and pass the transformed value as the result of the promise. For instance, I'd expect/want this to return an empty result set:
hooks: {
afterFind: function(result, options, fn)
{
result = [];
}
},
but it just causes the request to hang. Documentation says the arguments are pass by reference and doesn't include a return. Other samples imply something like:
hooks: {
afterFind: function(result, options, fn)
{
result = [];
return fn(null, result);
}
},
which doesn't hang, but doesn't change my result set. Not to mention, I've no idea what the magical "fn" argument is/does.
I had a similar problem. This is because when you do a findAll the argument passed to the hook is an array of values instead of a single object. I did this as a workaround -
hooks: {
afterFind: function(result) {
if(result.constructor === Array) {
var arrayLength = result.length;
for (var i = 0; i < arrayLength; i++) {
result[i].logo = "works";
}
} else {
result.logo = "works";
}
return result;
}
}
In the above code I change the logo attribute of the record(s) after finding it.

sequelize CreateAssociation return parent instance instead of child created instance

I have an issue with CreateAssociation method.
Here's my code :
User create curves
//User create curves
function saveCurves(user, functions){
var curves = JSON.parse(functions);
for (var i = 0; i < curves.length; i++) {
(function(i,user,curves){
user.createCurve({
i_min: curves[i].i_min,
i_max: curves[i].i_max,
}).then(function(curve){
saveFunction(curve,curves[i].fn,curves[i].variables);
});
})(i,user,curves);
}
}
//save function after creating curves depends on it
function saveFunction(curve,fct,variables){
return curve.createFunction({
fn: fct
}).then(function(math_function){
saveVariables(math_function,variables);
return;
})
}
//save variables to associated function
function saveVariables(fn, variables){
for(var j= 0; j < variables.length; j++){
(function(j,fn,variables){
fn.createVariable({
name: variables[j].name,
function_id: fn.id
})
.then(function(row_variable){
console.log(row_variable.toJSON())
return row_variable.createFunction({
fn: variables[j].fn
})
})(j,fn,variables);
}
I have an issue when I'm calling "fn.createVariable" Method.
I don't really understand why but the promise in .then just after give me fn instance instead of variable instance.
and also I have this error :
Unhandled rejection TypeError: row_variable.createFunction is not a function
When i'm looked into my database, I saw the instance has been correctly inserted
but row_variable in console.log give me fn and not inserted row.
So I cannot understand with I have this return.
I did it well above, so why it doesn't work here ?
(Not relation definition issue because row exist in database)
Any idea please ?

For loop in Swig template engine

I'm using Swig as a template engine for Express.js and I found no way to make a for loop with a variable like so:
for(var i=0; i<100; i++){
//whatever
}
Is this even possible?
As posted on your github issue for the same question, loops like this don't exist in Swig. You can iterate over actual objects and arrays, however. (See for-tag documentation).
Otherwise, you could create a range helper, as discussed here
swig.setDefaults({ locals: {
range: function (start, len) {
return (new Array(len)).join().split(',').map(function (n, idx) { return idx + start; });
}
}});

how to find specific string in key value pair in mongodb

i am having data in mongodb like that
[
{
"name":"silvester",
"product":"laptop,iphone,mobile,phone"
},
{
"name":"john",
"product":"cycle,bus,phone,laptop"
},
{
"name":"franklin",
"product":"cycle,phone"
}
]
How to find that laptop is in product key.
if product key look like this
{
"name":"XXX",
"product":"laptop"
}
I can easily find that name by using this db.collection.find("product":"laptop");
So how to find this?
Also let me know this three website name running under using backbone.js and node.js and mongodb technology such as www.trello.com .
sorry for my worst english..
Using regex with mongodb
This worked for me
db.collection.find({"product": /laptop/})
Updated Answer
If you wish to use variables, try something like this:
var abc = "laptop";
// other stuff
userdetails.find({"product":new RegExp(abc)}).toArray(function(err,result){
if (err) console.log ("error: "+err);
else
{
// if you want the length
console.log(result.length);
// if you actually want to see the results
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
}
}
});
Updated One More Time
var abc = "laptop";
// other stuff
// note this is case sensitive. if abc = "Laptop", it will not find it
// to make it case insensitive, you'll need to edit the RegExp constructor
// to this: new RegExp("^"+abc+",|, "+abc+"(?!\w)", "i")
userdetails.find({"product":new RegExp("^"+abc+",|, "+abc+"(?!\w)")}).toArray(function(err,result){
if (err) console.log ("error: "+err);
else
{
// if you want the length
console.log(result.length);
// if you actually want to see the results
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
}
}
});
regex will work perfectly fine. there is also good news for you as monogdb will be releasing full text search index in the upcoming version
http://docs.mongodb.org/manual/release-notes/2.4/#text-indexes

Resources