Shuffle bags on mongodb - node.js

I have an example of shuffle bags with node.js is like this:
var shuffle = {
bag:function () {
var data = [], cursor = -1;
return {
add: function (item, num) {
var i = num || 1;
while (i--) {
data.push(item);
}
cursor = data.length - 1;
},
next: function () {
var grab, temp;
if (cursor < 1) {
cursor = data.length - 1;
return data[0];
}
grab = Math.floor(Math.random() * (cursor + 1));
temp = data[grab];
data[grab] = data[cursor];
data[cursor] = temp;
cursor--;
return temp;
}
};
}
};
But, I want to make a shuffle bag with mongodb. Does someone know if mongodb has a native thing for converting an entire collection in a sufflebag of docs?

Related

nodejs performance timerify return instance instead of number

I was expected the timerify function to return a number,
but instead I got a function instance, with node v16.5.0:
function someFunction() {
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
return sum;
}
const perf = performance.timerify(someFunction);
const result = perf();
console.log(result);
result:
someFunction {}
const { performance, PerformanceObserver } = require("perf_hooks");
function someFunction() {
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
return sum;
}
const perf = performance.timerify(someFunction);
const obs = new PerformanceObserver((list) => {
console.log('duration :: ', list.getEntries()[0].duration);
performance.clearMarks();
obs.disconnect();
});
obs.observe({ entryTypes: ["function"] });
// A performance timeline entry will be created
const result = perf();
console.log('result :: ',result);

Worker threads are not running in Node.js

I am trying to implement a basic matrix multiplication using worker threads with a limit of 10 threads. But the threads which are not worker threads are not responding at all.
Matrix A and B are filled with random number generator.
if (isMainThread) {
const M = 100;
const N = 100;
const matrixA = [];
for (let i = 1; i <= M; i++) {
// random numbers for each element of mat A
}
const matrixB = [];
for (let i = 1; i <= M; i++) {
// random numbers for each element of mat B
}
let matCCount = 0;
const totalCount = (M * N);
const matrixC = [];
const time1 = new Date();
let threadCount = 0;
const calculateResult = (matrixC) => {
const time2 = new Date();
console.log(`\nTime taken: ${(time2 - time1) / 1000}s`);
}
const mainService = function(getResult) {
for (let i = 0; i < M; i++) {
for (let j = 0; j < N; j++) {
let success = false;
do {
if (threadCount < 11) {
const worker = new Worker(__filename, { workerData: { i, j, matrixA, matrixB } });
threadCount ++;
worker.on('message', (message) => {
getResult(message);
success = true;
threadCount --;
});
worker.on('online', () => { console.log('online'); })
worker.on('error', (err) => {
console.log(err);
});
worker.on('exit', (code) => { console.log(code); })
}
} while (!success);
}
}
}
mainService((res) => {
const { i, j, result } = res;
if (matrixC[i] === undefined) {
matrixC[i] = [];
}
matrixC[i][j] = result;
matCCount += 1;
if (matCCount === totalCount) {
calculateResult(matrixC);
}
});
} else {
const { i, j, matrixA, matrixB } = workerData;
const x = multiplyOperation(i, j, matrixA, matrixB);
parentPort.postMessage({ i, j, result: x, threadId });
}
neither 'online' event is fired nor this console.log runs
} else {
console.log(threadId);
const { i, j, matrixA, matrixB } = workerData;
const x = multiplyOperation(i, j, matrixA, matrixB);
parentPort.postMessage({ i, j, result: x, threadId });
}

DocumentDB, How to work with continuationToken in a SP

The next SP suppose to run over the collection and keep query for the next batch of documents (10 docs every batch). but instead return the same 10 documents every time.
function sample(prefix) {
var continuations = [],
ids = [],
context = getContext(),
collection = context.getCollection(),
response = context.getResponse();
var queryOptions = { pageSize: 10, continuation: null };
for (i = 0; i < 10; i++) {
// get all user wish list actions
var query = "select * from w",
accept = collection.queryDocuments(collection.getSelfLink(), query, queryOptions, processMultiUsers);
if (!accept) throw "Unable to read user's sessions";
}
getContext().getResponse().setBody(ids);
function processMultiUsers(err, docs, options) {
if (err) throw new Error("Error: " + err.message);
if (docs == undefined || docs.length == 0) throw new Error("Warning: Users not exists");
for (j = 0; j < docs.length; j++) {
ids.push(docs[j].UserId);
}
queryOptions.continuation = options.continuation;
continuations.push(options.continuation);
}}
In the script that you wrote, the execution of the queries are done synchronously and they are queued up with the same initial continuation token, which is null. Instead, we need to take the token from the first query and then queue the next and continue.
The below sample should help achieve what you are looking for
function sample(continuationToken) {
var collection = getContext().getCollection();
var maxResult = 10;
var documentsProcessed = 0;
var ids = [];
var filterQuery = "select * from w";
tryQuery(continuationToken);
function tryQuery(nextContinuationToken) {
var responseOptions = { continuation: nextContinuationToken, pageSize: maxResult };
if (documentsProcessed >= maxResult || !query(responseOptions)) {
setBody(nextContinuationToken);
}
}
function query(responseOptions) {
return (filterQuery && filterQuery.length) ?
collection.queryDocuments(collection.getSelfLink(), filterQuery, responseOptions, onReadDocuments) :
collection.readDocuments(collection.getSelfLink(), responseOptions, onReadDocuments);
}
function onReadDocuments(err, docFeed, responseOptions) {
if (err) {
throw 'Error while reading document: ' + err;
}
documentsProcessed += docFeed.length;
for (var i = 0; i < documentsProcessed; i++) {
ids.push(docFeed[i].UserId);
}
if (responseOptions.continuation) {
tryQuery(responseOptions.continuation);
} else {
setBody(null);
}
}
function setBody(continuationToken) {
var body = { continuationToken: continuationToken, documentsProcessed: documentsProcessed, ids: ids };
getContext().getResponse().setBody(body);
}
}

Random selection of rows in MongoDB async

So I have read the other posts on how to get a selection of random rows but none work for me.
Random record from MongoDB
and How to find random records in mongodb both suggest dated solutions that don't compile anymore.
Adding an extra random field to my database is not an option.
I've come up with the following code, but it also doesn't work.
exports.randomX = function(req, res)
{
var x = req.params.x;
db.collection('table', function(err, collection) {
collection.count(function(err, count) {
var r;
var arr = [];
for(var i=1; i<=x; i++)
{
r = Math.floor(Math.random() * count);
collection.find().limit(1).skip(r).toArray(function(err, items)
{
arr.push(items[0]);
if(arr.length === x)
res.send(arr);
});
}
});
});
}
Not sure if it's your only problem, but x will be a string, so if you want to compare it to arr.length you should either parse it into a number or just use == instead of ===.
exports.randomX = function(req, res)
{
var x = req.params.x;
db.collection('table', function(err, collection) {
collection.count(function(err, count) {
var r;
var arr = [];
for(var i=1; i<=x; i++)
{
r = Math.floor(Math.random() * count);
collection.find().limit(1).skip(r).toArray(function(err, items)
{
arr.push(items[0]);
if(arr.length == x)
res.send(arr);
});
}
});
});
}

Loop synchronous multiple async.whilst

I want to use many included loops in node.js in synchronous mode.
Example :
for (var i = 0; i < length1; i++) {
for (var j = 0; j < length2; j++) {
for (var k = 0; k < length3; k++) {
//completed 3
}
//completed 2
}
//do completed 1
}
How to do this with async? I tried this :
exports.myFunction = function (callback) {
var finalListA = new Array();
var pos = 0;
Model_A.find().populate('listOfItems')
.lean().exec(function (err, As) {
if (err) {
console.log(err);
return callback(err, null);
} else {
//For each A
var i = 0;
async.whilst(
function () {
return i < As.length;
},
function (callback1) {
var isActive = false;
//For each B into the A
var j = 0;
async.whilst(
function () {
return j < As[i].Bs.length;
},
function (callback2) {
Model_B.findById(AS[i].Bs[j]._id, function (err, B) {
if (err) {} else {
var k = 0;
// For each C in the B
async.whilst(
function () {
return k < B.Cs.length;
},
function (callback3) {
if (B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
}
k++;
callback3();
},
function (err) {
console.log("3 COMPLETED");
}
);
}
});
j++;
callback2();
},
function (err) {
console.log("2 COMPLETED");
if (err) {} else {
if (isActive == true) {
finalListA[pos] = As[i];
pos = pos + 1;
}
}
}
);
i++;
callback1();
},
function (err) {
console.log("1 COMPLETED");
if (err) {} else {
return callback(null, finalListA);
}
}
);
}
});
}
The trace shows me :
COMPLETED 2
COMPLETED 2
COMPLETED 1
COMPLETED 3
COMPLETED 3
The order expected is :
COMPLETED 3
COMPLETED 3
COMPLETED 2
COMPLETED 2
COMPLETED 1
You must call the callbacks of the higher loops from the end callback of your whilst loop (like you did with the outermost callback), instead of calling them synchronously from the whilst body in which you just started the next level iteration.
Btw, I don't know what you actually want to do, but whilst does not seem the best choice for iterating arrays. Use the parallel each or the serial eachSeries (or their map or reduce equivalents).
I've recently created simpler abstraction called wait.for to call async functions in sync mode (based on Fibers). It's at an early stage but works. It is at:
https://github.com/luciotato/waitfor
Using wait.for, you can call any standard nodejs async function, as if it were a sync function.
I do not understand exactly what are you trying to do in your code. Maybe you can explain your code a little more, or give some data example.
I dont' know what Model_A or Model_B are... I'm guessing most of your code, but...
using wait.for your code migth be:
var wait=require('wait.for');
exports.myFunction = function(callback) {
//launchs a Fiber
wait.launchFiber(inAFiber,callback);
}
function inAFiber(callback) {
var finalListA = new Array();
var pos = 0;
var x= Model_A.find().populate('listOfItems').lean();
As = wait.forMethod(x,"exec");
//For each A
for(var i=0;i<As.length;i++){
var isActive = false;
//For each B into the A
for(var j=0; j < As[i].Bs.length;j++){
var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
// For each C in the B
for(var k=0; k < B.Cs.length;k++){
if(B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
}
}
console.log("3 COMPLETED");
}
console.log("2 COMPLETED");
if(isActive == true) {
finalListA[pos] = As[i];
pos = pos + 1;
}
};
console.log("1 COMPLETED");
return callback(null,finalListA);
}
Also, for what I see, you should break the loops as soon as you find one item (isActive), and you don't need the var pos. Doing that your code will be:
var wait=require('wait.for');
exports.myFunction = function(callback) {
//launchs a Fiber
wait.launchFiber(inAFiber,callback);
}
function inAFiber(callback) {
var finalListA = [];
var x= Model_A.find().populate('listOfItems').lean();
As = wait.forMethod(x,"exec");
var isActive;
//For each A
for(var i=0;i<As.length;i++){
isActive = false;
//For each B into the A
for(var j=0; j < As[i].Bs.length;j++){
var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
// For each C in the B
for(var k=0; k < B.Cs.length;k++){
if(B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
break;//for each C
}
} //loop for each C
console.log("3 COMPLETED");
if (isActive) break;//for each B
} //loop for each B
if (isActive) finalListA.push(As[i]);
console.log("2 COMPLETED");
} //loop for each A
console.log("1 COMPLETED");
return callback(null,finalListA);
}

Resources