How can I compare data from two maps - node.js

I tried comparing data from each table from my data base but i failed
I'm not too familiar with react, I'm still working on it, I'm trying to compare the data from recommendation and customization and if they are the same I display them.
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
{
recommendation.map((rec, i) => {
customization.map((cus, j) => {
if (
rec.type === cus.type &&
rec.violonBody === cus.violonBody &&
rec.violonStick === cus.violonStick &&
rec.violonChincrest === cus.violonChincrest
) {
getCostumization();
}
});
});
}
});
Thank you!

You can use like below
const compare = (obj1, obj2) => {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
return keys1.every((key) => obj1[key] === obj2[key]);
};
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2}));
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2, c:3 }));

Comparing objects & array is not an easy task to do by ourselves since it involves doing deep comparison.
One of the popular and convenient way is to use the _.isEqual from the lodash library.
You could use it like this:
var object = { 'a': 1 };
var other = { 'a': 1 };
_.isEqual(object, other);
// => true
object === other;
// => false

Could you do something like this? This should return an array of objects that are found in both arrays:
function compareArrays(arr1, arr2) {
const same = [];
for (const i = 0; i < arr1.length; i++) {
for (const j = 0; j < arr2.length; j++) {
if (arr1[i].name === arr2[j].name) {
same.push(arr1[i]);
}
}
}
return same;
}
So using your example it would look like this:
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
const equalPairArray = compareArrays(recommendation, customization)
if(equalPairArray.length > 0){
getCostumization();
}
});

Related

why nested async/await doesn't work as intended?

I'm learning NodeJs and having some problems using async/ await. I'm using Firebase database to read/write data. Here what i'm doing. (full function in case you need it).
async getImport(reqData: any): Promise<any> {
const username = 'kdat0310';
const db = admin.database();
const userRef = db.ref('/user');
const importRef = db.ref('/import');
const refAuthentication = db.ref('/Authentication');
const keyList = [];
const providerKey = [];
const khoList = [];
let index = 0;
const providerList = [];
const isValid = await refAuthentication.once('value', function (snapshot) {
for (const val of Object.values(snapshot.val())) {
if (
Object(val).username === Object(reqData).username &&
Object(val).token === Object(reqData).token
) {
return true;
}
}
return false;
});
if (isValid) {
await userRef.once('value', function (snapshot) {
for (const value of Object.values(snapshot.val())) {
if (value) {
if (Object(value).username == username) {
for (const val of Object(value).workAt) {
if (val) khoList.push(val.khoId);
}
}
}
}
});
const typeAndColorKey = [];
const typeAndColorValue = [];
const typeAndColorRef = db.ref('/TypeAndColor');
await typeAndColorRef.once('value', function (snapshot) {
let count = 0;
for (const key in snapshot.val()) {
typeAndColorKey.push(key);
}
for (const value of snapshot.val()) {
if (value !== undefined && value != null) {
typeAndColorValue.push({
id: typeAndColorKey[count],
type: value.type,
color: value.color,
});
count = count + 1;
}
}
});
const findTypeAndColor = (id: any) => {
for (const value of typeAndColorValue) {
if (id == value.id) {
return { type: value.type, color: value.color };
}
}
};
const userKey = [];
const userList = [];
await userRef.once('value', function (snapshot) {
let count = 0;
for (const key in snapshot.val()) {
userKey.push(key);
}
for (const value of Object(snapshot.val())) {
if (value != undefined && value != null) {
userList.push({
id: userKey[count],
name: Object(value).name,
});
count++;
}
}
});
const findUserName = (userId: any) => {
const returnValue = '';
for (const value of userList) {
if (userId == Object(value).id) {
return Object(value).name;
}
}
};
const importList = [];
await importRef.once('value', async function (snapshot) {
const importKey = [];
const cloneArr = snapshot.val().map((item: any) => {
return item;
});
for (const key in snapshot.val()) {
importKey.push(key);
}
let countTemp = 0;
for (const value of Object.values(cloneArr)) {
const goodsKeyList = [];
let count = 0;
if (khoList.indexOf(Object(value).warehouseId) !== -1) {
const listGoodsList = [];
if (Object(value).listGoods) {
for (const key in Object(value).listGoods) {
goodsKeyList.push(key);
}
const refListGoods = db.ref(
'/import/' + importKey[countTemp] + '/listGoods',
);
await refListGoods.once('value', function (snapshot) {
let item: any;
for (item of Object.values(snapshot.val())) {
if (item) {
const tempItem = item.filter((n: any) => n);
listGoodsList.push({
typeAndColor: findTypeAndColor(goodsKeyList[count]),
listGoods: tempItem,
number: tempItem.length,
});
}
count++;
}
});
}
console.log('test 1', listGoodsList);
if (listGoodsList !== []) {
importList.push({
listGoods: listGoodsList,
driver: Object(value).driver,
userId: Object(value).importEmployee,
name: findUserName(Object(value).importEmployee),
orderId: Object(value).orderId,
warehouseId: Object(value).warehouseId,
time: Object(value).time,
});
}
}
countTemp++;
}
console.log('test 2', importList);
});
return importList;
}
return 'Invalid';
}
The problem show up when it came to await importRef.once When I tried to handle some data and add the Firebase once function "async" and await inside to push the data I need to the array. Then return importList; return nothing. I figure that the await refListGoods.once cause this problems. As i thought, the await inside had done its duty and I can console.log importList inside very well. But I thought that await importRef.once will finish before return too. when I delete await refListGoods.once, the return is fine but I dont get the data I need. Do I need to refactor all code as I do to findTypeAndColor and findUserName above or there's a better way to solve this problem?
If you want to use await on the Promise returned by once, you should not pass a callback function to it.
So instead of:
const isValid = await refAuthentication.once('value', function (snapshot) {
for (const val of Object.values(snapshot.val())) {
if (
Object(val).username === Object(reqData).username &&
Object(val).token === Object(reqData).token
) {
return true;
}
}
return false;
});
Do:
const snapshot = await refAuthentication.once('value');
let isValid = false;
snapshot.forEach((child) => {
const val = child.val();
if (val.username === Object(reqData).username &&
val.token === Object(reqData).token
) {
isValid = true;
}
})

Migrating from background page to service worker

In January 2023 the extensions with the Manifest V2 will stop working, and I try to migrate to V3 but I have the problem that I have to migrate to service worker
With the V2 manifest I had my background.js file
const browser = chrome || browser
const tabQuery = (options, params = {}) => new Promise(res => {
if (!options.countPinnedTabs) params.pinned = false
browser.tabs.query(params, tabs => res(tabs))
})
const windowRemaining = options =>
tabQuery(options, { currentWindow: true })
.then(tabs => options.maxWindow - tabs.length)
const totalRemaining = options =>
tabQuery(options)
.then(tabs => options.maxTotal - tabs.length)
const updateBadge = options => {
if (!options.displayBadge) {
browser.browserAction.setBadgeText({
text: "" })
return;
}
Promise.all([windowRemaining(options), totalRemaining(options)])
.then(remaining => {
browser.browserAction.setBadgeText({
text: Math.min(...remaining).toString()
});
chrome.browserAction.setBadgeBackgroundColor({
color: "#7e7e7e"
})
})
}
const detectTooManyTabsInWindow = options => new Promise(res => {
tabQuery(options, { currentWindow: true }).then(tabs => {
if (options.maxWindow < 1) return;
if (tabs.length > options.maxWindow) res("window");
});
})
const detectTooManyTabsInTotal = options => new Promise(res => {
tabQuery(options).then(tabs => {
if (options.maxTotal < 1) return;
if (tabs.length > options.maxTotal) res("total");
});
})
const getOptions = () => new Promise((res, rej) => {
browser.storage.sync.get("defaultOptions", (defaults) => {
browser.storage.sync.get(defaults.defaultOptions, (options) => {
res(options);
})
})
})
const displayAlert = (options, place) => new Promise((res, rej) => {
if (!options.displayAlert) { return res(false) }
const replacer = (match, p1, offset, string) => {
switch (p1) {
case "place":
case "which":
return place === "window" ?
"one window" : "total";
break;
case "maxPlace":
case "maxWhich":
return options[
"max" + capitalizeFirstLetter(place)
];
break;
default:
return options[p1] || "?";
}
};
const renderedMessage = options.alertMessage.replace(
/{\s*(\S+)\s*}/g,
replacer
)
alert(renderedMessage);
})
let tabCount = -1
let previousTabCount = -1
let amountOfTabsCreated = -1
const updateTabCount = () => new Promise(res => browser.tabs.query({}, tabs => {
if (tabs.length == tabCount) {
return res(amountOfTabsCreated);
}
previousTabCount = tabCount
tabCount = tabs.length
amountOfTabsCreated =
~previousTabCount ? tabCount - previousTabCount : 0
res(amountOfTabsCreated)
}))
let passes = 0;
const handleExceedTabs = (tab, options, place) => {
console.log(place)
if (options.exceedTabNewWindow && place === "window") {
browser.windows.create({ tabId: tab.id, focused: true});
} else {
browser.tabs.remove(tab.id);
}
}
const handleTabCreated = tab => options => {
return Promise.race([
detectTooManyTabsInWindow(options),
detectTooManyTabsInTotal(options)
])
.then((place) => updateTabCount().then(amountOfTabsCreated => {
if (passes > 0) {
console.log("passed with pass no. ", passes)
passes--;
return;
}
console.log("amountOfTabsCreated", amountOfTabsCreated)
displayAlert(options, place)
if (amountOfTabsCreated === 1) {
handleExceedTabs(tab, options, place);
app.update()
} else if (amountOfTabsCreated > 1) {
passes = amountOfTabsCreated - 1
} else if (amountOfTabsCreated === -1) {
handleExceedTabs(tab, options, place);
app.update()
} else {
throw new Error("weird: multiple tabs closed after tab created")
}
}))
}
const app = {
init: function() {
browser.storage.sync.set({
defaultOptions: {
maxTotal: 20,
maxWindow: 20,
exceedTabNewWindow: false,
displayAlert: true,
countPinnedTabs: false,
displayBadge: true,
alertMessage: chrome.i18n.getMessage("string_7")
}
});
browser.tabs.onCreated.addListener(tab =>
getOptions().then(handleTabCreated(tab))
)
console.log("init", this)
browser.windows.onFocusChanged.addListener(app.update)
browser.tabs.onCreated.addListener(app.update)
browser.tabs.onRemoved.addListener(app.update)
browser.tabs.onUpdated.addListener(app.update)
},
update: () => {
updateTabCount();
getOptions().then(updateBadge)
}
};
app.init();
app.update();
function capitalizeFirstLetter(string) {
return string[0].toUpperCase() + string.slice(1);
}
Any suggestions on how to convert it for service worker to work with Manifest V3?
Thank you and I look forward to your comments

I need help to get a simple query for MongoDB (SQL equivalent: "select speed from values")

I need help to get a simple query for MongoDB (SQL equivalent: "select speed from values"). But I can't find a solution for that.
Node.js backend for Vue.js
// a Part of Init-function:
await collection.replaceOne({}, {
speed: {
value: 65,
type: 2,
},
eightSpeed: {
value: 0.0043,
type: 2,
},
oSpeed: {
value: 0.31,
type: 2,
},
minusSpeed: {
value: 2.42,
type: 2,
}
}
//...
Now I need the query like this: http://192.168.220.220:3000/settings/getValue/speed to get an object speed.
const express = require("express");
const mongodb = require("mongodb");
const SettingsRouter = new express.Router();
SettingsRouter.get("/getValue/:value", async function (req, res) {
try {
const val = req.params.value; // req.body.text;
const select = {};
select[`${val}.value`] = 1;
console.log("settings.js:", "/getValue/:name", select);
const collection = await loadMongoCollection();
const value = await collection.findOne({},select)//.toArray();
res.status(201).send(value);
} catch (error) {
res.status(500).send("Failed to connect Database");
console.error("settings.js:", "/getValue/:name:", error);
}
});
async function loadMongoCollection() {
const dbUri = process.env.MONGODB_CONNSTRING || config.dbUri;
const MongoDB = process.env.MONGODB_DB || config.db;
try {
const client = await mongodb.MongoClient.connect(dbUri, {
useNewUrlParser: true,
});
const conn = client.db(MongoDB).collection("values");
return conn;
} catch (error) {
console.error("settings.js:", "loadMongoCollection:", error);
}
}
When I try it, I get all (not only the Speed Object) what I expected, or nothing.
What I do wrong?
EDIT 2022.01.06:
I try it to change my database:
data = {
speed: {
value: 65,
type: 2,
},//...
}
//...
await collection.replaceOne({}, {values:data}, { upsert: true });
And then the query:
const select = {[`values.${val}.value`]:"1"};
const where = {}; //{"values":val};
const value = await collection.find(where,select,).toArray();
But it will not work in rest... is there an issue in mongo package?
When I do it in https://cloud.mongodb.com - it works:
But my request returns all values...
Log shows:"'settings.js:', '/getValue/:name', { 'values.speed.value': '1' }"
In the screenshot you show the projection is values.speed.value, but in your endpoint you have:
const select = {};
select[`${val}.value`] = 1;
Which would evaluate to speed.value. To mimic what you have on the MongoDB console this should be:
const select = {};
select[`values.${val}.value`] = 1;
So, I changed my Frondend (vue) to spred all Values. I maked some Helper Functions:
CheckForChangedObj
check two object for changes
updateObj
copy all data from object into another
export function CheckForChangedObj(targetObject, obj) {
if (targetObject === typeof undefined || targetObject == {}) {
return true
}
if (JSON.stringify(targetObject) !== JSON.stringify(obj)) {
return true
}
return false
}
export function updateObj(targetObject, obj) {
let keys = Object.keys(obj)
for (let k in keys) {
try {
let key = keys[k]
if (!targetObject.hasOwnProperty(key)) {
//define target, if not exist
targetObject[key] = {}
}
//Workaround for References
if (obj[key].hasOwnProperty("__v_isRef")) {
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key].value
} else {
targetObject[key] = obj[key].value
}
} else {
//Source i a Norm Value
//check for an Object inside, then go in...
if ("object" === typeof obj[key] && !Array.isArray(obj[key])) {
updateObj(targetObject[key], obj[key]) // recurse
} else {
//not else-if!!! __v_isRef: true
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key]
} else {
targetObject[key] = obj[key]
}
}
}
} catch (error) {
console.log(
"key:",
keys[k],
"Error:",
error
)
}
}
}
Then spreading...
import {updateObj,CheckForChangedObj } from "../tools/tools"
beforeMount() {
this.getAllValuesAPI()
setInterval(() => {
this.checkForChanges()
// ml("TABLE", this.values)
}, 10000)
},
setup() {
let prevValues = {}
let values = {
speed: {
id:1,
type: SettingType.Slider,
value: ref(0)
}
//...
}
function checkForChanges() {
//intervaled function to get changes from API
let changed = CheckForChangedObj(this.values, this.prevValues)
if (changed) {
updateObj(this.prevValues, this.values)
setValuesToAPI()
}
else{
getAllValuesFromAPI()
}
}
async function getAllValuesFromAPI() {
//get ALL Settings-Data from API, and put them in values
const res = await axios.get(`settings/getAll`)
return updateObj(this.values, res.data[0].values) u
}
}
When you have a better solution, please help...

Why on my NodeJS+Express REST API a promise calling my function fails while the same promise with setTimeout works?

I have a NodeJS+Express REST API method executing reverse geocoding (using Google's Maps API).
I'm trying to solve it with Promises but the 'then' is getting executed before my function returns with the answers from Google.
When testing the same code just calling a setTimeout, it works as expected. Please see comments in the code (simplify version).
app.get('/api/v1/events', verifyToken, async (req, res) => {
await db.poolPromise.then(pool => {
return pool.request()
.input('UserId', db.sql.UniqueIdentifier, res.authData.userId)
.input('DateFrom', db.sql.DateTime2(7), req.query.dateFrom)
.input('DateTill', db.sql.DateTime2(7), req.query.dateTo)
.output('UserIdAuthorized', db.sql.Bit)
.execute('sp')
}).then(result => {
let output = (result.output || {})
if (!output.UserIdAuthorized) {
res.sendStatus(403)
}
else if (result.recordset.length > 0) {
(new Promise( (resolve) => {
//resolve(123) // this one works as expected
//setTimeout(resolve, 3000, 'temp success') // this one works as expected
// *** this one get passed and the following then is being executed before it answers ***
resolve( getAddress_TEST(result.recordset) )
// **************************************************************************************
})).then(function (value) {
res.json(
{
meta: { count: 10 }, //this is just a sample
result: value // *** this one fails with undefined ***
})
})
} else {
res.sendStatus(404)
}
}).catch(err => {
res.sendStatus(500)
console.error(err)
})
});
const nodeGeocoder_options = {
provider: 'google',
apiKey: process.env.GOOGLE_API_KEY
}
async function getAddress_TEST(recordset) {
//sample recordset for debugging - as you dont have my database
recordset = [{'eventId':14205556,'Lat':54.57767,'Lon':-2.4920483},{'eventId':14205558,'Lat':54.57767,'Lon':-2.492048},{'eventId':14205579,'Lat':53.416908,'Lon':-2.952071},{'eventId':14205588,'Lat':52.644448,'Lon':-1.153185},{'eventId':14205601,'Lat':52.29174,'Lon':-1.532283},{'eventId':14205645,'Lat':52.644448,'Lon':-1.153185},{'eventId':14205801,'Lat':53.68687,'Lon':-1.498708},{'eventId':14206041,'Lat':51.471521,'Lon':-0.2038033},{'eventId':14206049,'Lat':51.471521,'Lon':-0.2038033},{'eventId':14206072,'Lat':51.471521,'Lon':-0.2038033}]
let geocoder = nodeGeocoder(nodeGeocoder_options)
let ps = []
for (var i = 0, length = recordset.length; i < length; i++) {
if (i == 0 || !(i > 0
&& recordset[i - 1].Lat == recordset[i].Lat
&& recordset[i - 1].Lon == recordset[i].Lon)) {
ps.push(new Promise(function (resolve) {
resolve(reverseGeocode(geocoder, recordset[i].Lat, recordset[i].Lon))
}))
} else {
ps.push('-')
}
}
await Promise.all(ps)
.then(function (values) {
for (var i = 0, length = values.length; i < length; i++) {
if (values[i] != '-') {
recordset[i].locationAddress = values[i]
} else {
recordset[i].locationAddress = recordset[i - 1].locationAddress
}
}
}).then(function () {
recordset.forEach(function (v) {
delete v.Lat
delete v.Lon
});
console.log(recordset)
return recordset
})
};
async function reverseGeocode(geocoder, lat, lon) {
let address = '+'
if (lat != 0 && lon != 0) {
await geocoder.reverse({ lat: lat, lon: lon })
.then(res => {
address = res[0].formattedAddress
})
.catch(err => {
console.error(err)
});
}
return address
};
I'm sure it is something simple that I'm missing here...
The basic problem is that your getAddress_TEST function returns a promise that fulfills with nothing (undefined), because it does not contain a return statement. The return recordset is in a then() callback, from where it affects the promise resolution of the awaited promise, but that result is thrown away.
If you want to use async/await, you should get rid of any new Promise and then calls:
app.get('/api/v1/events', verifyToken, async (req, res) => {
try {
const pool = await db.poolPromise
const result = await pool.request()
.input('UserId', db.sql.UniqueIdentifier, res.authData.userId)
.input('DateFrom', db.sql.DateTime2(7), req.query.dateFrom)
.input('DateTill', db.sql.DateTime2(7), req.query.dateTo)
.output('UserIdAuthorized', db.sql.Bit)
.execute('sp')
let output = (result.output || {})
if (!output.UserIdAuthorized) {
res.sendStatus(403)
} else if (result.recordset.length > 0) {
const value = await getAddress_TEST(result.recordset)
res.json({
meta: { count: 10 }, //this is just a sample
result: value
})
} else {
res.sendStatus(404)
}
} catch(err) {
res.sendStatus(500)
console.error(err)
}
});
const nodeGeocoder_options = {
provider: 'google',
apiKey: process.env.GOOGLE_API_KEY
}
async function getAddress_TEST(recordset) {
const geocoder = nodeGeocoder(nodeGeocoder_options)
const ps = recordset.map((record, i) => {
if (i == 0 || !(i > 0
&& recordset[i - 1].Lat == record.Lat
&& recordset[i - 1].Lon == recordLon)) {
return reverseGeocode(geocoder, recordset[i].Lat, recordset[i].Lon))
} else {
return '-'
}
});
const values = await Promise.all(ps)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
for (var i = 0, length = values.length; i < length; i++) {
if (values[i] != '-') {
recordset[i].locationAddress = values[i]
} else {
recordset[i].locationAddress = recordset[i - 1].locationAddress
}
}
recordset.forEach(function (v) {
delete v.Lat
delete v.Lon
});
console.log(recordset)
return recordset
// ^^^^^^^^^^^^^^^^
}
async function reverseGeocode(geocoder, lat, lon) {
if (lat != 0 && lon != 0) {
const res = await geocoder.reverse({ lat: lat, lon: lon })
return res[0].formattedAddress
}
return '+'
}

How to test while loop code using jest and nodejs

I'm having a hard time doing some test on while loop using jest. This is the code I want to test but don't know how to do it.
const SHA256 = require('crypto-js/sha256')
class Block {
constructor(index, timestamp, data, prevHash = "") {
this.index = index
this.timestamp = timestamp
this.data = data
this.prevHash = prevHash
this.hash = this.calculateHash()
this.nonce = 0
}
calculateHash() {
return SHA256(this.index + this.prevHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString()
}
mineBlock(difficulty) {
while(this.hash.substring(0, difficulty) !== Array(difficulty + 1).join('0')) {
this.nonce++
this.hash = this.calculateHash()
}
}
}
module.exports = Block
This is what I've done so far
const Block = require('../block')
const BlockClass = new Block()
describe('Block Class', () => {
it('constructor', () => {
const obj = new Block(1, 2, 3, 4, 0)
expect(obj.index).toBe(1)
expect(obj.timestamp).toBe(2)
expect(obj.data).toBe(3)
expect(obj.prevHash).toBe(4)
expect(obj.nonce).toBe(0)
})
})
describe('hash', () => {
it('should be string', () => {
expect(typeof BlockClass.calculateHash()).toBe('string')
})
})
I'm pretty new with jest and unit testing and I find it really nice skills to have.
You can do something like this.
const Block = require('../block')
describe('mineBlock', () => {
let block = new Block()
it('should do <something>', () => {
block.mineBlock(5)
expect(block.nonce).toBe('<something>')
expect(block.hash).toBe('<something>')
})
})
Please replace <something> with real values you want.

Resources