Is there a nicer way to flatten two multi-value fields from a Notes document into a map collection in SSJS?
so far I came to the following:
var vw:NotesView = database.getView("configuration");
if(null != vw){
var doc:NotesDocument = vw.getFirstDocument();
if (null != doc){
var itemname1:string = "userName";
var itemname2:string = "inboxFile";
if(doc.hasItem(itemname1) && doc.hasItem(itemname2)){
var itemvalues1:java.util.Vector = doc.getItemValue(itemname1);
var itemvalues2:java.util.Vector = doc.getItemValue(itemname2);
if(itemvalues1.size() == itemvalues2.size()){
var map = new java.util.HashMap();
var iterator1 = itemvalues1.iterator();
var iterator2 = itemvalues2.iterator();
}
while (iterator1.hasNext()) {
var itemvalue1 = iterator1.next();
var itemvalue2 = iterator2.next();
if ((typeof(itemvalue1)).endsWith("string")) {
map.put(itemvalue1.left(80), itemvalue2.left(80));
}
}
sessionScope.put("setupInbox",map)
}
}
}
If the JavaScript forEach construct is supported you can use this:
function mergeVector(keyVector, valueVector) {
var map = new java.util.HashMap();
keyVector.forEach(function(curKey, index) {
if (index < valueVector.size()) {
map.put(curKey, valueVector.get(index));
}
});
return map;
}
otherwise use:
function mergeVector(keyVector, valueVector) {
var map = new java.util.HashMap();
for(var index = 0; index < keyVector.size(), index++) {
if (index < valueVector.size()) {
map.put(keyVector.get(index), valueVector.get(index));
}
};
return map;
}
Hope this helps
Related
I am writing a node JS web crawler class, and I have encountered the following error, this.textInvertedIndex[word].push is not a function. Upon further inspection I realised that for some reason this.textInvertedIndex[word] was written as a native object, function Object({ [native code] }). For the first few iterations, by console logging this.textInvertedIndex everything seemed fine as it was an object of arrays. But then suddenly this error occurred. Is there any part of the code where I am implicitly rewriting textInvertedIndex?
Here is the relevant class:
function Crawler(queue, maxIndexSize) {
this.queue = queue;
this.maxIndexSize = maxIndexSize;
this.findChunks = () => {
let currentChunk;
let minimumDistance = Infinity;
for (i = 1; i <= this.maxIndexSize; i++) {
if (this.maxIndexSize % i === 0) {
const newDistance = Math.abs(i - 30);
if (newDistance < minimumDistance) {
minimumDistance = newDistance;
currentChunk = i;
} else {
return currentChunk
};
};
};
};
this.chunks = this.findChunks();
this.chunkSize = this.maxIndexSize / this.chunks;
this.totalWordOccurances = {};
this.imageInvertedIndex = {};
this.textInvertedIndex = {};
this.images = [];
this.sites = [];
this.seen = {};
this.write = (url, html) => {
const documentId = this.sites.length;
const website = new Website(url, html);
const title = website.title();
const content = website.content(title);
const words = content.filter(item => typeof item !== "object");
const wordsLength = words.length;
const query = new Query(words);
const individualWords = query.individualize(words);
this.seen[url] = true;
this.sites.push({
url,
title,
description: website.description()
});
for (word of individualWords) {
const normalizedTf = query.count(word) / wordsLength;
const textInvertedIndexEntry = {
documentId,
normalizedTf
};
if (this.textInvertedIndex[word]) {
this.textInvertedIndex[word].push(textInvertedIndexEntry);
} else {
this.textInvertedIndex[word] = [textInvertedIndexEntry];
};
if (this.totalWordOccurances[word]) {
this.totalWordOccurances[word] += 1;
} else {
this.totalWordOccurances[word] = 1;
};
};
for (i = 0; i < content.length; i++) {
const item = content[i];
if (typeof item === "object") {
const imageId = this.images.length;
this.images.push(item);
for (word of individualWords) {
const imageScore = getImageScore(i, word, content);
const imageInvertedIndexEntry = {
imageId,
imageScore
};
if (this.imageInvertedIndex[word]) {
this.imageInvertedIndex[word].push(imageInvertedIndexEntry);
} else {
this.imageInvertedIndex[word] = [imageInvertedIndexEntry];
};
};
};
};
};
this.crawl = async () => {
while (this.sites.length !== this.maxIndexSize) {
let nextQueue = [];
const websitesUnfiltered = await Promise.all(this.queue.map((url) => {
const website = new Website(url);
return website.request();
}));
const websitesToAdd = this.maxIndexSize - this.sites.length;
let websites = websitesUnfiltered.filter(message => message !== "Failure")
.slice(0, websitesToAdd);
for (site of websites) {
const url = site.url;
const htmlCode = site.htmlCode;
const website = new Website(url, htmlCode);
this.write(url, htmlCode);
nextQueue = nextQueue.concat(website.urls());
};
nextQueue = new Query(nextQueue.filter(url => !this.seen[url]))
.individualize();
this.queue = nextQueue;
};
};
};
Called like this
const crawler = new Crawler(["https://stanford.edu/"], 25000000);
crawler.crawl();
this.textInvertedIndex = {}; is defining an Object of which push is not a valid function. you can change it to an array by defining it as this.textInvertedIndex = []; otherwise you can add key/value entries to the object as it is defined like this: this.textInvertedIndex[key] = value;
Turns out, my key was accessing this.textInvertedIndex[word]. And word was constructor. constructor is already a built in object property so it can never be rewritten as an array with .push defined. To solve this problem, make all object keys capital, so constructor will become CONSTRUCTOR, thus making sure that already existing object properties are never called.
I'm trying to write a user event script which loads the current record and populates a line item value through search after submit record. But, it is giving an error RCRD_DSNT_EXIST, even though the record exists.
function afterSubmit_SO(type){
try
{
//var record_type = nlapiGetRecordType();
var recordID = nlapiGetRecordId();
var context = nlapiGetContext();
var recordOBJ = nlapiLoadRecord('salesorder',recordID);
var source = context.getExecutionContext();
if(source == 'userinterface')
{
var line_count = recordOBJ.getLineItemCount('item');
nlapiLogExecution('DEBUG', 'line count ', line_count);
for(var i = 1; i <= line_count; i++)
{
var itemID = recordOBJ.getLineItemValue('item','item',i);
nlapiLogExecution('DEBUG', 'item ID', itemID);
var filter = new Array();
filter[0] = new nlobjSearchFilter('internalid', null, 'is', itemID);
var columns = new Array();
columns[0] = new nlobjSearchColumn('custitem_web_market_availability');
var a_search_results = nlapiSearchRecord('item',null,filter,columns);
if(a_search_results)
{
for(var x = 0; x < a_search_results.length; x++)
{
var item_web_availability = a_search_results[x].getText('custitem_web_market_availability');
nlapiLogExecution('DEBUG', 'value', item_web_availability);
}
} recordOBJ.setLineItemValue('item','custcol_web_item_availability',i,item_web_availability);
}
var submitID = nlapiSubmitRecord(recordOBJ, true, true);
}
}
catch(exception)
{
nlapiLogExecution('DEBUG','Exception Caught ','' + exception);
}
return true;
}```
It could be that your script is executing on the delete operation. I did not see any checking for this in the code you provided. If it is a delete operation then the after submit user event script wont be able to load the deleted record, this is why you get the error.
The type parameter of your afterSubmit function should contain the operation type. You can something like if (type == 'delete') { return true;} at the top of your script.
var feedData = [];
var listFeedQuery = pgFormat("select * from feedList where shopId=%L",shopId);
model.client.query(listFeedQuery,function(err,result){
if(result.rows.length > 0){
var triggerImageQuery = function(start,length,callback) {
var feedInfo = result.rows[start];
var imgQuery = pgFormat("select * from feedImages where feedId=%L",feedInfo.feedid);
model.client.query(imgQuery,function(err,result){
if(result.rows.length > 0){
var imgArr =[];
for(var j=0;j<result.rows.length;j++){
var image = "http://"+config.host+":"+config.port+"/"+result.rows[j].imageurl;
imgArr.push(image);
}
feedData.push(feedInfo);
feedData.push(imgArr);
}
else{
feedData.push(feedInfo);
}
console.log(feedInfo); // feedInfo have value
});
console.log(feedInfo); // feedInfo gets empty here
callback({'success':'1','result':{feedData},errorMessage:'No'});
if(start < length) {
start++;
triggerImageQuery(start, length-1);
}
}
triggerImageQuery(0, result.rows.length,function(result){
res.json(result);
});
}
else{
res.json({'success':'0','result':{},'errorMessage':'No feed available from the shop'});
}
});
feedData array is looks empty outside of a function?
its into looping(var feedInfo = result.rows[start];), so i unable to use the callback inside model.client.query. if i have callback inside model.client.query it will show the first set of details and return typeError : callback is not a function.
Try below codes. I have replaced the for...loop with a function logic.
var feedData = [];
var verifyShopQuery = pgFormat("select * from feedList where shopId=%L",shopId);
model.client.query(verifyShopQuery,function(err,result){
if(result.rows.length > 0){
var triggerImageQuery = function(start, length) {
var feeds = result.rows[start];
var imgQuery = pgFormat("select * from feedImages where feedId=%L",feeds.feedid);
model.client.query(imgQuery,function(err,result){
if(result.rows.length > 0){
var imgArr =[];
for(var j=0;j<result.rows.length;j++){
imgArr.push(result.rows[j].imageurl);
}
console.log(feeds,imgArr);
if(start < length) {
start++;
triggerImageQuery(start, length);
}
}
});
};
triggerImageQuery(0, result.rows.length);
}
else{
res.json({'success':'0','result':{},'errorMessage':'invalid shopId'});
}
I am enumerating all terms using SP.Taxonomy.js JSOM in SharePoint.While enumerating I want to check if currentTerm has children or not.I need some property to check like children count.How can I do this with minimum round trip to server.
I am using following code get taxonomy and it is working fine.
Please help
$(document).ready(function () {
ExecuteOrDelayUntilScriptLoaded(function () {
SP.SOD.registerSod('sp.taxonomy.js', "/_layouts/15/sp.taxonomy.js");
`SP.SOD.executeFunc('sp.taxonomy.js', false, Function.createDelegate(this,`
function () {
var context = SP.ClientContext.get_current();
var taxonomySession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
var termStore = taxonomySession.get_termStores().getByName("Taxonomy_qeFlDdEX32yZ3Q7EpEIeMQ==");
var termSet = termStore.getTermSet("ed6d3beb-6a49-4444-bc5d-456f747e139d");
var terms = termSet.getAllTerms();
context.load(terms);
context.executeQueryAsync(Function.createDelegate(this, function (sender, args) {
var termsEnumerator = terms.getEnumerator();
var menuItems = new Array();
while (termsEnumerator.moveNext()) {
var currentTerm = termsEnumerator.get_current();
var targetGroups = document.getElementById("selectTaxonomy");
var taxoGroup = document.createElement("option");
taxoGroup.text = currentTerm.get_name();
targetGroups.add(taxoGroup);
}
}), Function.createDelegate(this, function (sender, args) {
alert('The error has occured: ' + args.get_message());
}));
}));
},"sp.js")
});
You could use SP.Taxonomy.Term.termsCount property to get the number of child Term objects, for example:
var termSetId = '--guid goes here--';
getTerms(termSetId,
function(terms){
for(var i = 0;i < terms.get_count();i++){
var term = terms.get_item(i);
var hasChildTerms = (term.get_termsCount() > 0);
//...
}
},
function(sender,args)
{
console.log(args.get_message());
});
where
function getTerms(termSetId,success,error) {
var context = SP.ClientContext.get_current();
var taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
var termStore = taxSession.getDefaultSiteCollectionTermStore();
var termSet = termStore.getTermSet(termSetId);
var terms = termSet.getAllTerms();
context.load(terms);
context.executeQueryAsync(function () {
success(terms)
},
error);
}
Some recommendations
1) Prefer SP.SOD.loadMultiple function for loading multiple libraries, for example
SP.SOD.registerSod('SP.ClientContext', SP.Utilities.Utility.getLayoutsPageUrl('sp.js'));
SP.SOD.registerSod('SP.Taxonomy.TaxonomySession', SP.Utilities.Utility.getLayoutsPageUrl('sp.taxonomy.js'));
SP.SOD.loadMultiple(['SP.ClientContext', 'SP.Taxonomy.TaxonomySession'], function(){
//your code goes here
});
2) Avoid any hard-coding, for example:
/_layouts/15/sp.taxonomy.js -> SP.Utilities.Utility.getLayoutsPageUrl('sp.taxonomy.js')
Replace the line:
var termStore = taxonomySession.get_termStores().getByName("Taxonomy_qeFlDdEX32yZ3Q7EpEIeMQ==");
with this one:
var termStore = taxonomySession.getDefaultSiteCollectionTermStore();
Function.createDelegate Function could be avoided in most cases
I would like to start using Dynatree on my page, however I will probably need searching my tree by name. Do you know maybe how to do this?
I needed to have not only matching nodes, but also the whole paths to these nodes. I wrote this functionality and it works for me.
Modifications for library:
var clear = true;
DynaTreeNode.prototype.search = function(pattern){
if(pattern.length < 1 && !clear){
clear = true;
this.visit(function(node){
node.expand(true);
node.li.hidden = false;
node.expand(false);
});
} else if (pattern.length >= 1) {
clear = false;
this.visit(function(node){
node.expand(true);
node.li.hidden = false;
});
for (var i = 0; i < this.childList.length; i++){
var hide = {hide: false};
this.childList[i]._searchNode(pattern, hide);
}
}
},
DynaTreeNode.prototype._searchNode = function(pattern, hide){
if (this.childList){
// parent node
var hideNode = true;
for(var i = 0; i < this.childList.length; i++){
var hideChild = {hide: false};
this.childList[i]._searchNode(pattern, hideChild);
hideNode = hideNode && hideChild.hide;
}
if(hideNode && !this._isRightWithPattern(pattern)){
this._hideNode();
hide.hide = true;
} else {
hide.hide = false;
}
} else {
// leaf
if (!this._isRightWithPattern(pattern)){
this._hideNode();
hide.hide = true;
} else {
hide.hide = false;
}
}
},
DynaTreeNode.prototype._isRightWithPattern = function(pattern){
if((this.data.title.toLowerCase()).indexOf(pattern.toLowerCase()) >= 0){
return true;
}
return false;
},
DynaTreeNode.prototype._hideNode = function(){
if(this.li) {
this.li.hidden = true;
}
}
Use:
$("tree").dynatree("getRoot").search(pattern);
There is currently no search function, but you could use something like this (not tested)
var match = null;
tree.visit(function(node){
if(node.data.title === "foo"){
match = node;
return false; // stop traversal (if we are only interested in first match)
}
});
alert("Found " + match);
I've done it this way
<style>
span.occurance a.dynatree-title{background-color:#3AFF22;}
</style>
DynaTreeNode.prototype.find = function (needle) {
needle = (needle || '');
if (needle.length >= 1) {
var occurs = [];
this.visit(function (node) {
$(node.span).removeClass('occurance'); //remove pervious findings
if (node.data.title.indexOf(needle) != -1) {
occurs.push(node);
node._expandPath();
}
});
for (indx in occurs) { // mark findings
$(occurs[indx].span).addClass('occurance');
}
} else {
$('span.dynatree-node.occurance').removeClass('occurance');
}
},
DynaTreeNode.prototype._expandPath = function () {
var path = [],
node = this;
while (node = node.getParent()) {
path.push(node);
}
for (indx in path) {
path[indx].expand(true)
}
}
usage:
[your selector].dynatree("getRoot").find('needle');
Thanks to #mar10 i made a small, simple function to search a node with title:
// If searchFrom is null, root is used
function seachFolderNodeWithName(name, searchFrom) {
if (name == null) {
return undefined;
}
if (searchFrom == null) {
searchFrom = jQuery('#tree').dynatree("getRoot");
}
var match = undefined;
searchFrom.visit(function (node) {
if (node.data.title === name) {
match = node;
return false; // Break if found
}
});
return match;
};