Throw error in Mongoid - ruby-on-rails

Lets say i have this code:
map = %Q{
function() {
emit(this.name, { likes: this.likes });
}
}
reduce = %Q{
function(key, values) {
var result = { likes: 0 };
values.forEach(function(value) {
if(value.likes < 0){
#{Rails.logger.error "likes are negativ" }
}
result.likes += value.likes;
});
return result;
}
}
Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: true)
As you can see I want to record an error if the value.likes are negativ:
#{Rails.logger.error "likes are negativ" }
But this Code is executed each time I run the aggregate and not when the likes are negativ.
What can I do to throw an error in the aggregate statement?

Lets just analyze the code. Firstly:
map = %Q{
function() {
emit(this.name, { likes: this.likes });
}
}
Here a string is assigned to a variable map. Please not the %Q{} is just another way of writing "". Former is another syntax to easily define strings which have a double quote. e.g.
# pretty
%Q{He said "You are awesome"}
# not so pretty
"He said \"You are awesome\""
Next there is:
reduce = %Q{
function(key, values) {
var result = { likes: 0 };
values.forEach(function(value) {
if(value.likes < 0){
#{Rails.logger.error "likes are negative" }
}
result.likes += value.likes;
});
return result;
}
}
Here another string is assigned to a variable reduce. #{Rails.logger.error "likes are negative" } is just a regular string interpolation logging an error and returning true. So above code is equivalent to:
Rails.logger.error "likes are negative"
reduce = %Q{
function(key, values) {
var result = { likes: 0 };
values.forEach(function(value) {
if(value.likes < 0){
true
}
result.likes += value.likes;
});
return result;
}
}
You see why the logging statement is executed every time.
Next there is:
Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: true)
This is just a simple statement using mongoid to execute a map-reduce command on the mongo server, passing map and reduce functions constructed earlier.
Note that in above code, intention is to execute ruby code in a javascript reduce function. However that is not possible, as reduce function is being executed on mongodb server and cannot execute the logging statement.
One way to handle the situation could be to reduce to a hash like {likes: 0, negative_likes: 0}, incrementing negative_likes conditionally and logging error on receiving result.
PS: it might be a better idea to use aggregation framework instead of map-reduce.

Related

Neo4j transaction with array of queries with js-neo4j-driver

I want to pass an n-number of cypher-queries to a neo4j-transaction and I am thinking about a good approach.
At the moment I have a working approach that takes the array-item or if it is not available a dummy-query. (Code below)
I believe this is not best-practice. Does anybody know or have an idea how this can be done better?
function Neo4jTransaction(QueryArray) {
const session = driverWrite.session();
const tx = session.beginTransaction();
tx.run(QueryArray[0] || "RETURN 0")
tx.run(QueryArray[1] || "RETURN 0")
tx.run(QueryArray[2] || "RETURN 0")
tx.run(QueryArray[3] || "RETURN 0")
.then(result => {
return tx.commit()
}).then(() => {
session.close()
driverWrite.close()
}).catch(exception => {
console.log(exception)
session.close()
driverWrite.close()
})
}
First, if you have an array, you might want to iterate over it. Second, tx.run() returns a Promise that you need to catch if it fails. In your code, it is called 4 times in a row, but only the last one waits for the result and catches the error. I looks like some lines of the code are missing.
neo4j-driver documentation gives a good example on explicit transactions: https://github.com/neo4j/neo4j-javascript-driver#explicit-transactions
The queries are executed sequentially. If one fails the whole transaction will be rolled back.
async function neo4jTransaction(queryArray) {
const session = driver.session();
const txc = session.beginTransaction();
try {
for (const query of queryArray) {
await txc.run(query || 'RETURN 0');
}
await txc.commit();
} catch (e) {
await txc.rollback();
return Promise.reject(e);
} finally {
await session.close();
}
}

Issue with Zapier Code - Simple if else statement

I have looked over this countless times and yet I get the error "You must return a single object or array of objects.
if (inputData.score === '0') {
output = 'Passed';
} else {
output = 'Failed';
}
return output;
Not sure what I am doing wrong?
David here, from the Zapier Platform team.
In your code, you're returning a string, not a javascript object ({}) or array of objects ([{}, {}]).
change your code to the following:
if (inputData.score === '0') {
output = 'Passed';
} else {
output = 'Failed';
}
return {result: output};

selec2 search - Return no results found message if a specific criteria didnt match

I am using select2 4.0.3 for search drop down. As per my understanding its default functionality is not to match with the start of entries the drop down have. So I have implemented the below given code
function matchStart(params, data) {
params.term = params.term || '';
if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
return data;
}
return false;
}
$("select").select2({
placeholder : "Input country name or select region",
matcher : function (params, data) {
return matchStart(params, data);
},
});
My problem is, the dropdown is not showing "No results found" message even if there is no matching results found. Can anyone help me on this.
Thanks in advance.
Try changing the return value of matchStart from false to null.
Also you can remove the extra function around the matcher argument. The result:
function matchStart(params, data) {
params.term = params.term || '';
if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
return data;
}
return null;
}
$("select").select2({
placeholder: "Input country name or select region",
matcher: matchStart
});

Common way to execute a stored proc from both ColdFusion and Railo

I think I've gotten the most simplest scenario built. I just want to pass it by everyone for a sanity check. Here's the idea:
GetErrorCodes.cfm does the following:
<cfscript>
response = new ErrorCodes().WhereXXX(); // ACF or Railo, doesn't matter
</cfscript>
ErrorCodes.cfc:
function WhereXXX() {
return new sproc().exec('app.GetErrorCodes'); // All my functions will do this instead of executing the sproc themselves.
}
sproc.cfc:
component {
function exec(procedure) {
local.result = {};
if (server.ColdFusion.productname == 'Railo') {
return new Railo().exec(arguments.procedure); // Has to be outside of sproc.cfc because ColdFusion throws a syntax error otherwise.
}
local.svc = new storedProc();
local.svc.setProcedure(arguments.procedure);
local.svc.addProcResult(name='qry');
try {
local.obj = local.svc.execute();
local.result.Prefix = local.obj.getPrefix();
local.result.qry = local.obj.getProcResultSets().qry;
} catch(any Exception) {
request.msg = Exception.Detail;
}
return local.result;
}
Railo.cfc:
component {
function exec(procedure) {
local.result = {};
try {
storedproc procedure=arguments.procedure result="local.result.Prefix" returncode="yes" {
procresult name="local.result.qry";
}
} catch(any Exception) {
request.msg = Exception.Message;
}
return local.result;
}
}
So I've been working on this all day, but tell me, is this a sane way to keep the source code the same if it's to be run on either a ColdFusion server or a Railo server?
Um... just use <cfstoredproc> instead of trying to use two different CFScript approaches that are mutually exclusive to each other of the CFML platforms.

Criteria building in GORM

if (params.filters) {
def o = JSON.parse(params.filters);
def groupOp = o.groupOp
def fields = o.rules.field
def values = o.rules.data
def op = o.rules.op
println fields
println values
if(groupOp == "AND") {
fields.eachWithIndex {a, i ->
println op[i]
if(op[i].equals( "eq")) {
and{ eq(fields[i], values[i])}
}
if(op[i].equals("ne")) {
and{ ne(fields[i], values[i])}
}
if(op[i].equals("ge")) {
def valu = Double.valueOf( values[i]);
and{ ge(fields[i], valu)}
}
}
}
if(groupOp == "OR") {
fields.eachWithIndex {a, i ->
println op[i]
if(op[i].equals( "eq")) {
println 'eq';
or{ eq(fields[i], values[i])}
}
if(op[i].equals("ne")) {
println 'ne';
or{ ne(fields[i], values[i])}
}
if(op[i].equals("ge")) {
def valu = Double.valueOf( values[i]);
or{ ge(fields[i], valu)}
}
}
}
}
where params.filters is following JSON text.
{
"groupOp":"OR",
"rules":[
{
"field":"foo1",
"op":"le",
"data":"9.5"
},
{
"field":"foo2",
"op":"eq",
"data":"12345-123"
},
{
"field":"foo3",
"op":"cn",
"data":"IDM"
}
]
}
This data is coming from JQuery data grid.
Is there a better way of doing this?
In the code I have just listed only 3 operators, but in real I have 14 operations.
You can use String as Criteria operation, like:
A.withCriteria {
'eq' (id, 1)
}
so you might come to something like
A.withCriteria {
(groupOp) {
for (???) {
(op[i]) (fields[i], parsedVals[i])
}
}
}
Anyway you'll need to sanitize the web-submitted query for only allowed subset of operations. You don't want to receive end execute arbitrary sqlRestriction, right? :D So the code is going to be more complex then this anyway.
Note: wrapping and{} or or {} around single statement has no point, you need to put it around whole block of if-s.
I suggest that you have a look at the source code of the FilterPane plugin. Its service does essentially what you are doing and may give you some ideas for enhancements.

Resources