Sort by best matches mongodb - mongodb

I have collection of data in Mongodb, i want to give best matches suggestion while user input query in our suggestion box,
when user start typing com suggestion should be:
Computer
Computer Science
something more alike
I am sorting in Node by getting all matched data from mongo first and then give a rank to each data
function rank(name, q) {
var len = name.length,
lastIndex = -1;
for(var i = 0; i < q.length; i++) {
var n = name.indexOf(q[i], (lastIndex + 1));
if(n !== -1) {
len--;
lastIndex = n;
}
}
return len;
}
var query = 'com';
// giving rank to data
data = data.map(function(v) {
v.rank = rank(v.value, query);
return v;
});
// sorting by rank
data = data.sort(function(a, b) {
return a.rank - b.rank
});
It is giving me satisfied result, but it will be too slow while dealing with large data.
I want let mongodb engine to deal with sorting and give me just limited best matches result.

Maybe you could do it through mapreduce. Map-reduce is a data processing paradigm for condensing large volumes of data into useful aggregated results.
var mapFn = function(){
var len = this.name.length,
lastIndex = -1;
var q = 'com';
for(var i = 0; i < q.length; i++) {
var n = this.name.indexOf(q[i], (lastIndex + 1));
if(n !== -1) {
len--;
lastIndex = n;
}
}
emit(len, this);
};
var reduceFn = function(key, values){
return values.sort(function(a,b){
return a.name - b.name;
});
};
db.collection.mapReduce(mapFn, reduceFn, { out: { reduce: 'result_collection'}});

Related

Audioworklet loop

I'm trying to create an audioworklet that loops a single instance of a sound to create a sort of sustain effect. No matter how many sections of the input I loop, I keep hearing a blip type skipping sound. How many calls to the processor is one instance?
To give you an idea, this is what I have so far:
constructor() {
super();
this.sound = [];
this.count = 20;
this.step = [0, 0];
}
process(inputs, outputs, parameters) {
if (inputs && inputs.length) {
for (var i = 0; i < inputs[0].length; i++) {
var input = inputs[0][i];
var output = outputs[0][i];
if (!this.sound[i]) {
this.sound[i] = [];
}
if (this.sound[i].length < this.count) {
this.sound[i].push([]);
for (var j = 0; j < input.length; j++) {
this.sound[i][this.sound[i].length - 1][j] = input[j];
}
} else if (this.sound[i]) {
var s = this.sound[i][this.step[i] % this.sound[i].length];
for (var j = 0; j < s.length; j++) {
output[j] = s[j];
}
this.step[i]++;
}
}
}
return true;
}
So the idea is that I capture the incoming input in an array of N length for each channel(in my case there are 2 channels). Then once that array is full, I cycle through that array to fill the output until the node is disabled.
Thanks for the fiddle. Very helpful.
I didn't look to see what was causing the clicks, but I took your example and modified it very slightly like so:
// #channels 2
// #duration 1.0
// #sampleRate 44100
var bufferSize = 4096;
let ctx = context;
let osc = ctx.createOscillator();
osc.start();
let myPCMProcessingNode = ctx.createScriptProcessor(bufferSize, 2, 2);
let _count = 1;
var sound = [];
var count = _count++;
console.log(count)
var hesitate = 0;
var step = [0, 0];
//Logic to pay attention to
myPCMProcessingNode.onaudioprocess = function(e) {
for(var i = 0; i<2; i++){
var input = e.inputBuffer.getChannelData(i);
var output = e.outputBuffer.getChannelData(i);
if (!sound[i]) {
sound[i] = [];
}
if (sound[i].length < count) {
sound[i].push([]);
for (var j = 0; j < input.length; j++) {
sound[i][sound[i].length - 1][j] = input[j];
}
} else if (sound[i]) {
var s = sound[i][step[i] % sound[i].length];
for (var j = 0; j < s.length; j++) {
output[j] = s[j];
}
step[i]++;
}
}
}
//To hear
osc.connect(myPCMProcessingNode).connect(ctx.destination);
I pasted this in the code window at https://hoch.github.io/canopy. Press the top left button (arrow) to the left of the code window, and you can see the rendered audio. You can see that the output (frequency is 10 instead of 440 to make it easier to see) is discontinuous. This causes the clicks you hear. You can also change the frequency to 100 and find discontinuities in the output.
I hope this is enough to help you figure out what's wrong with your buffering.
An alternative is to create an AudioBufferSourceNode with an AudioBuffer of the basic sample. You can set the AudioBufferSourceNode to loop the whole buffer. This doesn't solve the clicking problem, but it is somewhat simpler.
But this is a general problem of looping any buffer. Unless you arrange the last sample to be close to the first sample, you will hear clicks when you wrap around. You either need to grab chunks where the first and last samples are nearly the same, or modified the chunks so they ramp up at the beginning in some way and ramp down at the end in some way.

How to loop and collect MultiInput values?

I am using sap.m.MultiInput. How to send that data to the SAP Backend?
I tried using a loop:
for(var i = 0; i < oLenght; i++) {
var oData = this.getView().byId("myMultiInputControl").getTokens()[i].getKey();
}
But oData is holding always a new value. How to hold the data?
you can use a delimiter for example ("/" character) between the keys of the multinput and send the data to the backend System :
if(oMultiInputElement.tokens.length > 1) {
var dataToSend = "";
for(var i = 0; i < oMultiInputElement.tokens.length; i++) {
dataToSend = oFilterData.tokens[i].key + "/" + dataToSend;
}
} else {
dataToSend = oMultiInputElement.tokens[0].key;
}

Arithmetic operation between Meteor Helpers

I am handling a new Meteor test project and came across a doubt.. Please try to find a solution for me.
This application has 2 'helpers' for the same template.
Template.scoreBoard.helpers({
scroeHalfTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreHalf)});
return sum;
},
scroeFullTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreFull)});
return sum;
}
I would like to return the difference between this 'scroeHalfTime' and 'scroeFullTime', this will give me a result of how much did the player scored before and after half time.
Following codes did not work for me..
{{ScroeFullTime - scroeHalfTime}}
{{ScroeFullTime() - scroeHalfTime()}}
{{(ScroeFullTime - scroeHalfTime)}}
Simply create variable which will hold both values, like
var halfTime=0, fullTime=0;
Template.scoreBoard.helpers({
scroeHalfTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreHalf)});
halfTime = sum;
return sum;
},
scroeFullTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreFull)});
fullTime = sum;
return sum;
},
difference: function(){
return fullTime - halfTime;
}
Simple call {{scoreFullTime - scoreHalf Time}}. You can do that inside the template.
Solved..
Created Another Helper, and now Template. scoreBoard.helpers looks like,
Template.scoreBoard.helpers({
scroeHalfTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreHalf);
});
return sum;
},
scroeFullTime:function(){
var cursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var sum = 0;
cursor.forEach(function(player){
sum = sum + Number(player.scoreFull)});
return sum;
},
scoreDifference:function(fullTime,halfTime){
var halfCursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var halfScore = 0;
halfCursor.forEach(function(player){
halfScore = halfScore + Number(player.scoreHalf);
})
var fullCursor = return MyCollection.find({player:"selectedPlayer"}).fetch();
var fullScore = 0;
fullCursor.forEach(function(player){
fullScore = fullScore + Number(player.scoreFull);
})
});
return fullScore - halfScore;
}
});

Google Spreadsheet - How to avoid sending email duplicates?

I am having an issue with a script. I used the following script from Google Developers Website in order to do a simple merge mail. See https://developers.google.com/apps-script/articles/mail_merge
I modified a bit the script so to prevent email duplicates. However, even if the script seems to work as it marks 'EMAIL_SENT' in each row every time an email is sent. It does not pay attention if the mail as already been marked and still send the mail.
I believe there is an error at line 16 "var emailSent = rowData[6];"
I would really appreciate if someone could help me. Whoever you are thanks in advance.
Here is the modified script :
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 7);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A2").getValue();
var objects = getRowsData(dataSheet, dataRange);
for (var i = 0; i < objects.length; ++i) {
var Resume = DriveApp.getFilesByName('Resume.pdf') var Portfolio = DriveApp.getFilesByName('Portfolio.pdf') var rowData = objects[i];
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Architectural Internship";
var emailSent = rowData[6];
if (emailSent != EMAIL_SENT) {
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText, {
attachments: [Resume.next(), Portfolio.next()]
});
dataSheet.getRange(2 + i, 7).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
function fillInTemplateFromObject(template, data) {
var email = template;
var templateVars = template.match(/\${\"[^\"]+\"}/g);
for (var i = 0; i < templateVars.length; ++i) {
var variableData = data[normalizeHeader(templateVars[i])];
email = email.replace(templateVars[i], variableData || "");
}
return email;
}
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
var numColumns = range.getEndColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
function normalizeHeader(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue;
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
// Returns true if the cell where cellData was read from is empty. // Arguments: // - cellData: string function isCellEmpty(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise. function isAlnum(char) { return char >= 'A' && char <= 'Z' || char >= 'a' && char <= 'z' || isDigit(char); }
// Returns true if the character char is a digit, false otherwise. function isDigit(char) { return char >= '0' && char <= '9'; }
Your code is really hard to read and the functions that return 2 or more objects make it even harder...you are using variable names that are also a bit confusing.... but that is probably a personal pov :-)
Anyway, I think I've found the issue: when you write var rowData = objects[i];
This "object" is actually the result of the getRowData function but if you look at this function, you'll see that it returns 2 objects, the first one being itself the result of another function (getObjects) ...
You are checking the value is the 6th element of the array which is actually an object and compare it to a string. The equality will never be true.
I didn't go further in the analyse since I found it really confusing ( as I already said) but at least you have a first element to check .
I would suggest you rewrite this code in a more simple way and use more appropriate variable names to help you while debugging.
I would recommend logging both values before executing to make sure they are the same. I would also guess that the email_sent and EMAIL_SENT are different data types. Can also try forcing the value to string for comparison.
To clarify:
logger.Log(emailSent);
logger.Log(EMAIL_SENT);
if (emailSent.toString() != EMAIL_SENT.toString())
{...
Error is in this line of code -
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
It's considering only 2 columns in the range. Changed 2 to 3 and it worked fine.

mongodb map emit keys from subdocument

I have a document which includes a subdocument:
{
"_id" : ObjectId("XXXXX"),
"SearchKey" : "1234",
"SearchTerms" : {
"STA" : ["1"],
"STB" : ["asdfasdf"],
"STC" : ["another"]
}
}
The SearchTerm elements are not fixed - sometimes we'll have STA without STC, for example.
I can do this:
var map = function() {
for (key in this.SearchTerms)
{
emit(key, 1);
}
}
but I can't do this:
var map = function() {
for (var i=0; i< this.SearchTerms.length; i++)
{
emit(this.SearchTerms[i], 1)
}
}
because the latter doesn't produce any results after the reduce. Why not?
As an aside - what I need to do is count the cross-product of the search terms over all documents, that is, find the incidence of (STA and STB) and (STA and STC) and (STB and STC) in the case above. If someone knows how to do that right away, that works even better.
As always, thanks for the help
The key that you emit should be a composite of both keys.
var map = function() {
if(!this.SearchTerms) return;
for(var i = 0 ; i < this.SearchTerms.length; i++){
var outerKey = this.SearchTerms[i];
for(var j = i + 1; j < this.SearchTerms.length; j++){
var innerKey = this.SearchTerms[j];
// assuming you don't care about counting (STA and STC) separately from (STC and STA),
// then order doesn't matter, lets make sure both occurences have the same key.
var compositeKey = (outerKey < innerKey) ? outerKey+"_"+innerKey : innerKey+"_"+outerKey;
emit(compositeKey, 1);
}
}
}
This is because this.SearchTerms is a dictionary/subdocument and not an array. this.SearchTerms[0] doesn't exist.
For the second question: something like this should work:
for (key1 in this.SearchTerms)
{
for (key2 in this.SearchTerms)
{
if (key1 < key2)
{
key = [key1, key2];
emit(key, 1);
}
}
}