I am writing a script in 2.0, here is the snippet.
var resultSet = [];
var result = search.load({
id:'customsearch_autosend_statement_invoice'
}).run().each(function( item ) {
resultSet.push(item);
});
If I run this saved search in the normal interface I get lots of rows like 2000 plus, but if I run this code I get back 1 row, even using the each function and adding the items to another array I only get one row. I don't see anything in the documentation about this. Can anyone tell me why this is? I'm stumped. thanks in advance for any help
I found the answer but not because I should have seen it, the examples don't make any attempt to tell you that you have to return true from the each method in order to keep receiving rows. So the answer is that at the end of the "each" function you must return a true value to receive the next row. Like this, so thanks for your effort if I miss your post.
var resultSet = [];
var result = search.load({
id:'customsearch_autosend_statement_invoice'
}).run().each(function( item ) {
resultSet.push(item);
return true;
});
It's detailed in the documentation, the callback function returns a boolean which can be used to stop or continue the iteration:
Use a developer-defined function to invoke on each row in the search
results, up to 4000 results at a time. The callback function must use
the following signature: boolean callback(result.Result result); The
callback function takes a search.Result object as an input parameter
and returns a boolean which can be used to stop the iteration with a
value of false, or continue the iteration with a value of true.
...
mySearch.run().each(function(result) {
var entity = result.getValue({
name: 'entity'
});
var subsidiary = result.getValue({
name: 'subsidiary'
});
return true;
});
...
ResultSet.each(callback)
Related
Edit:I wrote a query that should return all items where ticked is true. I try to set the count of tickedItemsQuery but it tells me count is not an function. numChildren is also not a function. How can I set the count of the query?
exports.tickedBoxesCount = functions.database.ref('/listItems/{list_id}').onWrite(event => {
const ref = event.data.ref.parent;
const list_id = event.params.list_id;
const tickediItemsQuery = ref.orderByChild("ticked").equalTo(true)
admin.database().ref(`/lists/${list_id}/tickedCount`).set(tickediItemsQuery.count());
});
This line of code creates a query:
const tickediItemsQuery = ref.orderByChild("ticked").equalTo(true)
Note that it does not execute the query, it merely defines it. So there's no way that you can know the number of matching children from merely this line.
To determine the count, you'll need to execute the query, and determine the number of children in the resulting snapshot:
return tickediItemsQuery.once("value").then(function(snapshot) {
return admin.database().ref(`/lists/${list_id}/tickedCount`).set(snapshot.numChildren());
});
Note that I also added necessary return statements, to ensure the Cloud Functions knows when your (asynchronous) read and write operations are done.
I'm trying to add a paragraph at the end of the document and escape the possibility of the newly added paragraph to be added inside a list (if the document is ending with a list).
I have the following code:
let paragraph = paragraphs.items[paragraphs.items.length - 1]
let p = paragraph.insertParagraph('', window.Word.InsertLocation.after)
if (paragraph.listItemOrNullObject) {
p.detachFromList()
p.leftIndent = 0
}
The following happens: if there is a ListItem, the code works. If not, it breaks inside the if condition, like I wrote paragraph.listItem.
Shouldn't this be used like this?
EDIT - error thrown:
name:"OfficeExtension.Error"
code:"GeneralException"
message:"GeneralException"
traceMessages:[] 0 items
innerError:null
â–¶debugInfo:{} 4 keys
code:"GeneralException"
message:"GeneralException"
toString:function (){return JSON.stringify(this)}
errorLocation:"Paragraph.detachFromList"
the issue here is that the *.isNullObject methods/properties does not return a regular js 'null' object, but a NullObject (a special framework type of null).
check out this code i rewrote it i think in a more efficient way. excuse my js, you can port it to ts.
hope this helps.
Word.run(function (context) {
var listI = context.document.body.paragraphs.getLast().listItemOrNullObject;
context.load(listI);
return context.sync()
.then(function () {
if (listI.isNullObject) { // check out how i am validating if its null.
console.log("there is no list at the end")
}
else {
context.document.body.paragraphs.getLast().detachFromList();
context.document.body.paragraphs.getLast().leftIndent = 0;
return context.sync();
}
})
})
listItemOrNullObject will return a null object if it isn't a ListItem. Conceptually you're if is asking "if this is a list item or it isn't a list item" which effectively will also return true.
It is failing here you are attempting to detach from a non-existent list. I would take a look at isListItem. This will tell you specifically if the paragraph is a ListItem so you only execute p.detachFromList() when in fact it is part of a list.
There are two collections products and stock in my database.Each product have multipple stock with different supplier and attributes of products.
I have selected the products from products collection and run a loop for each product. I need to append price and offer price from the stock collection to products i have selected already.
I think the for loop compleated its execution before executiong the find method on stock collection.I need to execute everything in the loop in serial manner(not asynchronous). Please check the code below and help me to solve this. I'm new in node.js and mongodb
collection = db.collection('products');
collection.find().toArray(function(err, abc) {
var finalout = [];
for( var listProducts in abc){
var subfinal = {
'_id' :abc[listProducts]['_id'],
'min_price' :abc[listProducts]['value']['price'],
'stock' :abc[listProducts]['value']['stock'],
'name' :abc[listProducts]['value']['name'],
'price' :'',
'offer_price' :'',
};
collection = db.collection('stock');
collection.find({"product":abc[listProducts]['_id'] ,"supplier":abc[listProducts]['value']['def_supplier']}).toArray(function(err, newprod) {
for( var row in newprod){
subfinal['price'] = newprod[row]['price'];
subfinal.offer_price = newprod[row]['offer_price'];
}
finalout.push(subfinal);
});
}
console.log(finalout);
});
Yes, the loop is running and starting the get requests on the database all at the same time. It is possible, like you said, to run them all sequentially, however it's probably not what you're looking for. Doing it this way will take more time, since each request to Mongo would need to wait for the previous one to finish.
Considering that each iteration of the loop doesn't depend on the previous ones, all you're really looking for is a way to know once ALL of the operations are finished. Keep in mind that these can end in any order, not necessarily the order in which they were initiated in the loop.
There's was also an issue in the creation of the subfinal variable. Since the same variable name is being used for all iterations, when they all come back they'll be using the final assignment of the variable (all results will be written on the same subfinal, which will have been pushed multiple times into the result). To fix that, I've wrapped the entire item processing iteration into another function to give each subfinal variable it's own scope.
There are plenty of modules to ease this kind of management, however here is one way to run some code only after all the Mongo calls are finished using a counter and callback that doesn't require any additional installs:
var finished = 0; // incremented every time an iteration is done
var total = Object.keys(abc).length; // number of keys in the hash table
collection = db.collection('products');
collection.find().toArray(function(err, abc) {
var finalout = [];
for( var listProducts in abc){
processItem(listProducts);
}
});
function processItem(listProducts) {
var subfinal = {
'_id' :abc[listProducts]['_id'],
'min_price' :abc[listProducts]['value']['price'],
'stock' :abc[listProducts]['value']['stock'],
'name' :abc[listProducts]['value']['name'],
'price' :'',
'offer_price' :'',
};
collection = db.collection('stock');
collection.find({"product":abc[listProducts]['_id'] ,"supplier":abc[listProducts]['value']['def_supplier']}).toArray(function(err, newprod) {
for( var row in newprod){
subfinal['price'] = newprod[row]['price'];
subfinal.offer_price = newprod[row]['offer_price'];
}
finalout.push(subfinal);
finished++;
if (finished === total) { // if this is the last one to finish.
allFinished(finalout);
}
});
}
function allFinished(finalout) {
console.log(finalout);
}
It could be written more concisely with less variables, but it should be easier to understand this way.
Today I've faced interesting problem of create test for pretty simple behavior: 'Most recent' sorting. All what test need to know:
Every item have ID
Previous ID is less then next in this case of sorting
Approach: writing ID in to attribute of item, getting that id from first item with getAttribute() and either way for second.
Problem: getAttribute() promise resulting with string value and Jasmine is not able to compare (from the box) string numbers.
I would like to find elegant way to compare them with toBeLessThan() instead of using chains of few .then() that will be finished with comparing that things.
Root of no-type-definition evil
Thanks guys <3
You can create a helper function to convert string number to actual number, which will make use of Promises:
function toNumber(promiseOrValue) {
// if it is not a promise, then convert a value
if (!protractor.promise.isPromise(promiseOrValue)) {
return parseInt(promiseOrValue, 10);
}
// if promise - convert result to number
return promiseOrValue.then(function (stringNumber) {
return parseInt(stringNumber, 10);
});
}
And then use the result with .toBeLessThan, etc:
expect(toNumber(itemId)).toBeLessThan(toNumber(anotherItemId));
I forgot of native nature of promises but tnx to Michael Radionov I've remembered what I want to do.
expect(first.then( r => Number(r) )).toBe(next.then( r => Number(r) ));
I guess this stroke looks simple.
UPDATE
ES6:
it('should test numbers', async function () {
let first = Number(await $('#first').getText());
let second = Number(await $('#second').getText());
expect(first).toBeGreaterThan(second);
})
One option to approach it with a custom jasmine matcher:
toBeSorted: function() {
return {
compare: function(actual) {
var expected = actual.slice().sort(function (a, b) {
return +a.localeCompare(+b);
});
return {
pass: jasmine.matchersUtil.equals(actual, expected)
};
}
};
},
Here the matcher takes an actual input array, integer-sort it and compare with the input array.
Usage:
expect(element.all(by.css(".myclass")).getAttribute("id")).toBeSorted();
Note that here we are calling getAttribute("id") on an ElementArrayFinder which would resolve into an array of id attribute values. expect() itself is patched to implicitly resolve promises.
chrome.storage.sync.get('savedItem', function (result) {
//some if else condition for result.savedItem here
myResult = result.savedItem;
});
$('p').val(myResult);
With above code, I got an undefined, because there is no setting been saved in my options page for the first time user. I tried to set a default value to myResult like if(result.savedItem == undefined) myResult = ''; but I still got undefined. Why?
2 issues at the same time.
1) You can set default for values not in the storage by providing a dictionary:
chrome.storage.sync.get({'savedItem' : 'myDefault'}, function (result) {
// result.savedItem is the saved value or 'myDefault'
});
2) The biggest issue is not understanding how asynchronous code works.
$('p').val(myResult); gets executed before myResult is assigned, because chrome.storage.sync.get returns immediately, with the function(result){...} being called later.
There have been tons of questions about that, take a look at, say, this and this.
Use chrome storage change - Refer this link
Example code:
chrome.storage.onChanged.addListener(function(changes, namespace) {
for (var key in changes) {
var storageChange = changes[key];
console.log('Storage key "%s" in namespace "%s" changed. ' + 'Old value was "%s", new value is "%s".', key, namespace, storageChange.oldValue, storageChange.newValue);
}
});