Here is the structure of my firebase database:
/UserData
/DeviceMgmt
/Counters
/NumberOfAll:
/NumberOfSelected
/TotalDownloaded
...
/Devices
/pushId1
/uid
/signOutTime
/toSelect=true (optional)
/downloaded
/lastDownload
/pushId2
/pushId3
...
And this is my cloud function:
exports.markDevicesForDownload = functions.database.ref('/UserData/DeviceMgmt/Counters/NumberOfSelected').onUpdate( (change) => {
const changeRef = change.after.ref;
const deviceMgmtRef = changeRef.parent.parent; // /UserData/DeviceMgmt
if (change.after.val() === 0 ) { //NumberOfSelected gets 0 value
return deviceMgmtRef.once('value')
.then((snap) => {
const devicesRef = snap.child('Devices').ref;
var average;
var numberOfAllDevices;
var totalDownloaded;
numberOfAllDevices = snap.child('Counters/NumberOfAll').val();
totalDownloaded = snap.child('Counters/TotalDownloaded').val();
average = Math.round(totalDownloaded/numberOfAllDevices);
return devicesRef
.orderByChild('signOutTime')
.equalTo(0)
.once('value',(devices) => {
return devices.ref
.orderByChild('downloaded')
.endAt(average)
.once('value',(devices) => {
devices.forEach((device) => {
device.child('toSelect').ref.set(true);
});
});
});
});
} else {
return false;
}
});
The function triggers when the counter NumberOfSelected = 0;
This happens when under any of device pushId there is no child toSelect. Then the query on downloaded child makes all devices with downloaded less than average set toSelect=true.
I wanted to limit the devices only to those which have signOutTime equal 0.
Somehow that query does not work and all devices are considered.
What I did wrong???
I would push all async tasks into a promise array and then return them all when all tasks complete:
exports.markDevicesForDownload = functions.database.ref('/UserData/DeviceMgmt/Counters/NumberOfSelected').onUpdate((change) => {
const changeRef = change.after.ref;
const deviceMgmtRef = changeRef.parent.parent; // /UserData/DeviceMgmt
if (change.after.val() === 0) { //NumberOfSelected gets 0 value
return deviceMgmtRef.once('value')
.then((snap) => {
const promises = [];
const devicesRef = snap.child('Devices').ref;
var average;
var numberOfAllDevices;
var totalDownloaded;
numberOfAllDevices = snap.child('Counters/NumberOfAll').val();
totalDownloaded = snap.child('Counters/TotalDownloaded').val();
average = Math.round(totalDownloaded / numberOfAllDevices);
const dR = devicesRef
.orderByChild('signOutTime')
.equalTo(0)
.once('value', (devices) => {
const dW = devices.ref
.orderByChild('downloaded')
.endAt(average)
.once('value', (devices) => {
devices.forEach((device) => {
if (device.child("signOutTime").val() === 0){
promises.push(device.child('toSelect').ref.set(true));
}
});
});
promises.push(dW);
});
promises.push(dR);
return Promise.all(promises);
});
} else {
return false;
}
});
Related
I am new to Nodejs. I am developing WebAPI by using NodeJs and MSSQl as database.My api is giving proper response in case of POST endpoint If it is called while server is listening through Dev environment command [npm run start]. But, If I Deploy my API on Windows IIS , it is giving the mentioned error. My reference API endpoint code is as below :
router.post('/',async (req,res,next)=>{
// console.log('Enter products creation')
const Product = Array.from(req.body) // req.body
// console.log('New Product details passed on',Product)
const createProd = require('../CreateProduct')
const response = await createProd(Product)
res.status(404).json({
message : response.retStatus
})
})
CreateProduct function called in above code is as below :
const sql = require("mssql/msnodesqlv8");
const dataAccess = require("../DataAccess");
const fn_CreateProd = async function (product) {
let errmsg = "";
let objBlankTableStru = {};
let connPool = null;
// console.log('Going to connect with Connstr:',global.config)
await sql
.connect(global.config)
.then((pool) => {
global.connPool = pool;
productsStru = pool.request().query("DECLARE #tblProds tvp_products select * from #tblProds");
return productsStru;
})
.then(productsStru=>{
objBlankTableStru.products = productsStru
productsOhStru = global.connPool.request().query("DECLARE #tblprodsOh tvp_product_oh select * from #tblprodsOh");
return productsOhStru
})
.then((productsOhStru) => {
objBlankTableStru.products_oh = productsOhStru
let objTvpArr = [
{
uploadTableStru: objBlankTableStru,
},
{
tableName : "products",
tvpName: "tvp_products",
tvpPara: "tblProds"
},
{
tableName : "products_oh",
tvpName: "tvp_product_oh",
tvpPara: "tblProdsOh",
}
];
newResult = dataAccess.getPostResult(
objTvpArr,
"sp3s_ins_products_tvp",
product
);
console.log("New Result of Execute Final procedure", newResult);
return newResult;
})
.then((result) => {
// console.log("Result of proc", result);
if (!result.recordset[0].errmsg)
errmsg = "New Products Inserted successfully";
else errmsg = result.recordset[0].errmsg;
})
.catch((err) => {
console.log("Enter catch of Posting prod", err.message);
errmsg = err.message;
if (errmsg == "") {
errmsg = "Unknown error from Server... ";
}
})
.finally((resp) => {
sql.close();
});
return { retStatus: errmsg };
};
module.exports = fn_CreateProd;
GetPost() function is as below :
const getPostResult = (
tvpNamesArr,
procName,
sourceData,
sourceDataFormat,
singleTableData
) => {
let arrtvpNamesPara = [];
let prdTable = null;
let newSrcData = [];
// console.log("Source Data :", sourceData);
let uploadTable = tvpNamesArr[0];
for (i = 1; i <= tvpNamesArr.length - 1; i++) {
let tvpName = tvpNamesArr[i].tvpName;
let tvpNamePara = tvpNamesArr[i].tvpPara;
let TableName = tvpNamesArr[i].tableName;
let srcTable = uploadTable.uploadTableStru[TableName];
srcTable = srcTable.recordset.toTable(tvpName);
let newsrcTable = Array.from(srcTable.columns);
newsrcTable = newsrcTable.map((i) => {
i.name = i.name.toUpperCase();
return i;
});
if (!singleTableData) {
switch (sourceDataFormat) {
case 1:
newSrcData = sourceData.filter((obj) => {
return obj.tablename.toUpperCase() === TableName.toUpperCase();
});
break;
case 2:
newSrcData = getObjectDatabyKey(sourceData, TableName);
break;
default:
newSrcData = getTableDatabyKey(sourceData, TableName);
break;
}
} else {
newSrcData = sourceData;
}
// console.log(`Filtered Source data for Table:${TableName}`, newSrcData);
prdTable = generateTable(
newsrcTable,
newSrcData,
tvpName,
sourceDataFormat
);
arrtvpNamesPara.push({ name: tvpNamePara, value: prdTable });
}
const newResult = execute(procName, arrtvpNamesPara);
return newResult;
};
Finally, I have found the solution to this.. it is very strange and shocking and surprising that If I using Morgan Middleware in app.js and have used it by syntax : app.use(morgan('dev')) , then it is the culprit command..I just removed dev from this command after which problem got resolved..But I found no help regarding this issue over Google anywhere..I really fear that what type of challenges I am going to face in future development if these kind of silly error come without giving any hint..I would be highly obliged If anyone could make me understand this kind of silly errors..
I had to do 2 messageCollector on my bot, and both have boolean filters to check if the message is able to be collected. But i want that only one collector can be used per time. So, if the person choose the collector 2, i will put his id on an array, and if this id is in the array, the first collector wont be called. When the second collector finish, i put an event "end" to remove the respective id from the array, so he can use the collector 1 again. but isnt working the code is
----- ignore module -----
let ignore = [];
const addIgnore = (message)=>{
ignore.push(message.from)
}
const removeIgnore = (message)=>{
ignore = ignore.filter(ignored=>ignored !== message.from)
}
module.exports={ignore,addIgnore,removeIgnore}
-----first collector code ----
const Response = require('./Response')
const {ignore}= require('./utils/handleIgnore')
const HandleMessageCollector=async (client,message)=>{
const filter = m => m.from === message.from &&;
const collector = client.createMessageCollector(message.from, filter, {max: 10,time: 1000 * 60 })
if (ignore.includes(message.from)) {
return
}
else {
const b64ify = (obj) => Buffer.from(JSON.stringify(obj)).toString('base64');
const options =["Agendar","Local","Promoçoes","Serviços", "Falar com o atendente", "Curso"]
await client.sendListMessage(message.from,[{
title:"Opções",
rows:options.map(option =>({
title:option,
rowId:b64ify({option})
}))
}],"Olá, Tudo bem? Sou o assistente virtual do salão MAURO CHRISOSTISMO. ","Selecione uma das opções","Opções")
await collector.on('collect',
async (m) => {
if (m) {
const mensagem = m.content
switch (mensagem) {
case "Agendar":
await Response.AGENDAR(client,message)
return ;
case "Local":
await Response.LOCAL(client,message); //envia a localização
collector.stop((msg) => { return msg })
return ;
case "Promoçoes":
Response.PROMO(client,message)// Envia as promocoes
collector.stop((msg) => { return msg })
return
case "Serviços":
await client.sendText(message.from, "Em construção")
collector.stop((msg) => { return msg })
return;
case "Falar com o atendente":
Response.ATEND(client,message) // Responseposta do atendimento
return;
case "Curso":
default:
await client.sendText(message.from,`opção inválida`);
collector.stop((msg)=>{return msg})
}
}
})
await collector.on("end",()=>{
})
}
}
module.exports=HandleMessageCollector
--- the second collector ---
const {addIgnore,removeIgnore}=require("../utils/handleIgnore")
const AgendarCollector=async (client,message)=>{
addIgnore(message)
const question = ['Qual o seu nome?','Qual o dia? Formato = dd/mm','Qual o profissional?','Qual o serviço?'];
let counter = 0
const filter = m => m.from === message.from;
const collector = client.createMessageCollector(message.from, filter, {max:4,time: 1000 * 60 })
await client.sendText(message.from,question[counter++])
await collector.on('collect',
async (m) => {
if (m) {
if(counter<question.length){
await client.sendText(message.from,question[counter++])
}
}
})
await collector.on('end', async(all)=>{
let finshed = [];
removeIgnore(message)
if(all.size<question){
console.log('não terminado')
}
await all.forEach(one=>finshed.push(` ${one.content}`))
await client.sendText(message.from,`${finshed}.\nConfirma?`)
})
}
module.exports=AgendarCollector
what im doing wrong?
I'm trying to filter some data by themes and am puzzled as to how I can go about doing it. Say I have two items with the themes ['People', 'Technology', 'Culture'] and ['Economy', 'Technology', 'Culture'], if the query is Technology, I am able to see both of these items appearing. But if the query is Technology and Culture, I'm not able to see either of them because ["Technology", "Culture"] =/= ['People', 'Technology', 'Culture'] and vice versa. My code searches for the exact list, not it's components, if the query was Technology and Culture then I want both of those items to show up since it is inside that list.
I'm not sure how to do this, I'm using MERN stack and here is my backend code:
const Project = require('../models/projectModel')
const mongoose = require('mongoose')
// get all projects
const getProjects = async (req, res) => {
const projects = await Project.find().sort({ createdAt: -1 })
// const test = await Project.find({assignment_type: 1 || 2}).sort({ createdAt: -1 })
// console.log(test)
res.status(200).json(projects)
}
// get filtered project
const getFilteredProjects = async (req, res) => {
var request = {}
console.log(req.query.sdg)
console.log('t' + req.query.theme)
console.log('a' + req.query.assignment_type)
// var t = ["Economical", "Technological"]
// const test = await Project.find({theme: ("Technological" && "Economical")}).sort({ createdAt: -1 })
// const test = await Project.find({
// $and:
// }).sort({ createdAt: -1 })
// console.log(test)
// Function to separate commas from string
function separateCommas(str) {
let t = []
for (let i = 0; i < str.length; i++) {
if (str[i] === ',') {
console.log(i)
t.push(i)
}
}
let themeArray = []
if (t.length === 1) {
let theme1 = str.slice(0, t[0])
let theme2 = str.slice(t[0]+1)
themeArray.push(theme1)
themeArray.push(theme2)
}
if (t.length === 2) {
let theme1 = str.slice(0, t[0])
let theme2 = str.slice(t[0]+1, t[1])
let theme3 = str.slice(t[1]+1)
themeArray.push(theme1)
themeArray.push(theme2)
themeArray.push(theme3)
}
request["theme"] = themeArray.sort()
}
// See if sdg selected
if (req.query.sdg !== '') {
request["sdg"] = req.query.sdg
}
// See if assignment type selected
if (req.query.assignment_type !== '') {
request["assignment_type"] = req.query.assignment_type
}
// See if theme selected
if (req.query.theme !== '') {
if (req.query.theme.length > 14) {
separateCommas(req.query.theme)
}
else {
request["theme"] = req.query.theme
}
}
console.log(request)
const projects = await Project.find(request).sort({ createdAt: -1 })
res.status(200).json(projects)
}
module.exports = {
getProjects,
getProject,
createProject,
deleteProject,
updateProject,
getFilteredProjects
}
This is how my backend code receives the data from the database, it sends it in this format where there can be multiple theme's:
{
sdg: 'SDG 2: Zero Hunger',
assignment_type: 'Discussion Topics',
theme: 'Economy'
}
How's it going?
I got the example order book code in python (https://support.kraken.com/hc/en-us/articles/360027677512-Example-order-book-code-Python-) and translate it to javascript to run in node. But the book is wrong, it doesn't remove all old prices level. I'm sending my code below. I'd like help to solve this issue.
const websocket = require('ws');
const ws = new websocket('wss://ws.kraken.com');
const api_book = {'bid':[], 'ask':[]};
const api_depth = 10;
const api_output_book = () => {
bid = api_book['bid'].sort((x, y) => parseFloat(y[0])-parseFloat(x[0]));
ask = api_book['ask'].sort((x, y) => parseFloat(x[0])-parseFloat(y[0]));
console.log ('Bid\t\t\t\t\tAsk');
for (let x=0;x<api_depth;x++) {
console.log(`${bid[x][0]} (${bid[x][1]})\t\t\t${ask[x][0]} (${ask[x][1]})`);
}
}
const api_update_book = (side, data) => {
data.forEach((e) => {
let index = api_book[side].findIndex(o => o[0] == e[0]);
if (parseFloat(e[1]) > 0){
if(index < 0){
api_book[side].push([e[0],e[1]]);
} else {
api_book[side][index] = [e[0],e[1]];
}
} else {
api_book[side].splice(index,1);
}
});
if(side=='bid'){
api_book['bid'].sort((x, y) => parseFloat(y[0])-parseFloat(x[0]));
} else if(side=='ask'){
api_book['ask'].sort((x, y) => parseFloat(x[0])-parseFloat(y[0]));
}
}
ws.on('open', open = () => {
ws.send('{"event":"subscribe", "subscription":{"name":"book", "depth":'+api_depth+'}, "pair":["XBT/USD"]}');
console.log('Kraken websocket connected!');
});
ws.on('message', incoming = (data) => {
try {
data = JSON.parse(data.toString('utf8'));
if (data[1]) {
if (data[1]['as']) {
api_update_book('ask', data[1]['as'])
api_update_book('bid', data[1]['bs'])
} else if (data[1]['a'] || data[1]['b']) {
if (data[1]['a']) {
api_update_book('ask', data[1]['a']);
}
if (data[1]['b']) {
api_update_book('bid', data[1]['b']);
}
}
api_output_book();
}
} catch (error) {
console.log(error);
}
});
So I have also been playing around with Kraken's order book and came up with this solution using Angular. I also added a few console logs into the mix so that you can take it and run it in the browser. Hope this helps!
// variables
private ws = new WebSocket('wss://ws.kraken.com')
public asks = [];
public bids = [];
// Web Socket open connection
this.ws.onopen = () => {
this.ws.send(JSON.stringify(this.message));
console.log('Trade WS with Kraken connected')
}
// Fires when new data is received from web socket
this.ws.onmessage = (event) => {
var data = JSON.parse(event.data);
if (!data.event) {
if (data[1]['as']) {
this.asks = data[1]['as'];
this.bids = data[1]['bs'];
console.log('Initialised Book');
console.log(this.asks, this.bids);
} else if (data[1]['a'] || data[1]['b']) {
if (data[1]['a']) {
this.update_book(this.asks, 'ask', data[1]['a']);
}
if (data[1]['b']) {
this.update_book(this.bids, 'bid', data[1]['b']);
}
}
}
}
// Updating Orderbook
update_book (arr, side, data) {
if (data.length > 1) { // If 2 sets of data are received then the first will be deleted and the second will be added
let index = arr.findIndex(o => o[0] == data[0][0]); // Get position of first data
arr.splice(index, 1); // Delete data
arr.push([ data[1][0], data[1][1] ]); // Insert new data
console.log('Delete and Insert');
} else {
let index = arr.findIndex(o => o[0] == data[0][0]);
console.error(index);
if (index > -1) { // If the index matches a price in the list then it is an update message
arr[index] = [data[0][0], data[0][1]]; // Update matching position in the book
console.log('Updated ' + index);
} else { // If the index is -1 then it is a new price that came in
arr.push([data[0][0], data[0][1]]); // Insert new price
this.sort_book(arr, side); // Sort the book with the new price
arr.splice(10, 1); // Delete the 11th entry
console.log('Insert Only');
}
}
this.sort_book(arr, side); // Sort the order book
}
// Sort Orderbook
sort_book (arr, side) {
if (side == 'bid') {
arr.sort((x, y) => parseFloat(y[0]) - parseFloat(x[0]));
} else if (side == 'ask') {
arr.sort((x, y) => parseFloat(x[0]) - parseFloat(y[0]));
}
}
I would also recommend just having a look at this resource:
How to maintain a valid orderbook
I am using Cloud Functions for Firebase together with my Firebase Realtime Database in order to do some data management for my app.
One of my functions though seems to get terminated since it takes about 100-150 seconds to complete. This happens with error : ESOCKETTIMEDOUT.
Is there a way to prevent this?
Here is my function:
function getTopCarsForUserWithPreferences(userId, genres) {
const pathToCars = admin.database().ref('cars');
pathTocars.orderByChild("IsTop").equalTo(true).once("value").then(function(snapshot) {
return writeSuggestedCars(userId, genres, snapshot);
}).catch(reason => {
console.log(reason)
})
}
function writeSuggestedCars(userId, genres, snapshot) {
const carsToWrite = {};
var snapCount = 0
snapshot.forEach(function(carSnapshot) {
snapCount += 1
const carDict = carSnapshot.val();
const carGenres = carDict.taCarGenre;
const genre_one = genres[0];
const genre_two = genres[1];
if (carGenres[genre_one] === true ||carGenres[genre_two] == true) {
carsToWrite[carSnapshot.key] = carDict
}
if (snapshot.numChildren() - 1 == snapCount) {
const pathToSuggest = admin.database().ref('carsSuggested').child(userId);
pathToSuggest.set(carsToWrite).then(snap => {
}).catch(reason => {
console.log(reason)
});
}
});
}
The getTopCarsForUserWithPreferences gets called when a user adds preferences. Also the cars table has about 50k entries.
Well you need to return everytime you use a async task.
Edit: you return 'writeSuggestedCars' but I think it never returns a value. I do not have a compiler, but I thought it was return Promise.resolved(). Can you insert it where I putted 'HERE'?
Maybe this will work:
function getTopCarsForUserWithPreferences(userId, genres) {
const pathToCars = admin.database().ref('cars');
return pathTocars.orderByChild("IsTop").equalTo(true).once("value").then(function(snapshot) {
return writeSuggestedCars(userId, genres, snapshot);
}).catch(reason => {
console.log(reason)
})
}
function writeSuggestedCars(userId, genres, snapshot) {
const carsToWrite = {};
var snapCount = 0
snapshot.forEach(function(carSnapshot) {
snapCount += 1
const carDict = carSnapshot.val();
const carGenres = carDict.taCarGenre;
const genre_one = genres[0];
const genre_two = genres[1];
if (carGenres[genre_one] === true ||carGenres[genre_two] == true) {
carsToWrite[carSnapshot.key] = carDict
}
if (snapshot.numChildren() - 1 == snapCount) {
const pathToSuggest = admin.database().ref('carsSuggested').child(userId);
return pathToSuggest.set(carsToWrite).then(snap => {
// 'HERE' I think return promise/Promise.resolve() will work
}).catch(reason => {
console.log(reason)
});
}
});
}