How is this JavaScript object somehow converted to a string? - javascript

I have been working on a Node.JS/MongoDB backend for a product catalogue system and I have run into a weird bug.
The Process
First I load the product information from the product collection. This product contains information such as its name, description and also a list of file upload IDs that point to images of the product in an array of strings.
I then, for each upload ID, load the information for each photo. I then replace the array of upload ID strings with an array of file information objects.
However, when I output the resulting product object, the list of images is a list of strings that represent JavaScript as if they were written in code.
The Code
// products.controller.js
async function populateImageInformation(productRecord) {
let imageInfo = [];
for(let uploadId of productRecord.images) {
let imageData = await File.getByUploadId(uploadId);
imageInfo.push(imageData);
console.log(typeof imageData); // => object
}
console.log(typeof imageInfo); // => object
console.log(typeof imageInfo[0]); // => object
productRecord.images = imageInfo;
console.log(typeof productRecord.images); // => object
console.log(typeof productRecord.images[0]); // => string
return productRecord;
}
async function getAll(req, res, next) {
try {
let productRecords = await Product.find({});
for(let productRecordI in productRecords) {
productRecords[productRecordI] = await populateImageInformation(productRecords[productRecordI]);
}
res.json(productRecords);
} catch (e) {
next(e);
}
}
Mongoose schema file:
// file.model.js
getByUploadId: function(uploadId) {
return this.findOne({
uploadId
});
}
I do not understand that when I set the productRecord.images property to imageInfo the values in the array suddenly become string representations of the values.
The string does not contain JSON, but instead contains a human-readable string representation of how an object is hard-coded into JavaScript. These strings cannot be parsed as JSON at all. JSON expects keys to be wrapped in double quotes whereas the JavaScript code produced doesn't have this.
Is there any reason for this to happen? I have never seen this occur.

The problem is due to mongoose schema , they protect the model by types you declared in schema . Object Returning by find is a mongoose model, they do type check when you update any value on it.
Let's come to your scenario . I have created an example . See below
const mongoose = require('mongoose');
const db = require('./db');
const Schema = mongoose.Schema;
const productSchema = new Schema({
name: {type: String},
images: [String] // Note schema have array of string
});
const productModel = mongoose.model('product', productSchema);
db.connect().then(() => {
//find record from productSchema
return productModel.find({})
.then((productRecords) => { //productRecords - don't forget is a mongoose model object
// productRecords from db [{"name":"gilette","images":["idx","idy"],"_id":"5ac324c4fad317265b9df226","__v":0}]
//TRIAL A
for (let productRecordI in productRecords) {
productRecords[productRecordI] = populateImageInformation(productRecords[productRecordI]);
}
console.log(typeof productRecords[0].images[0]); //=> string;
//SOLUTION for the problem is copy mongoose data without reference
//TRIAL B
productRecords = JSON.parse(JSON.stringify(productRecords));
for (let productRecordI in productRecords) {
productRecords[productRecordI] = populateImageInformation(productRecords[productRecordI]);
}
console.log(typeof productRecords[0].images[0]); //=> Object;
});
//just a mock function change images to object
function populateImageInformation(productRecord) {
imageInfo = [];
for (let uploadId of productRecord.images) {
let imageData = {name: uploadId};
imageInfo.push(imageData);
console.log(typeof imageData); // => object
}
productRecord.images = imageInfo;
return productRecord;
}
}).catch((err) => {
console.log('err', err);
});

Related

Can't update firebase collection field - Expected type 'ya', but it was: a custom Ia object

I am trying to make barbershop web app where costumer can see list of free appointments and when they reserve free appointment I want to delete that field from firebase.
I have a collection which represents one barber.
This is how it looks in firebase.
As you see radno_vrijeme is object or map in firebase which contains 6 arrays, and in each array there is list of free working hours.
In my function I am able to do everthing except last line where I need to update firebase collection.
const finishReservation = async () => {
try {
const freeTimeRef = collection(db, `${barber}`);
const q = query(freeTimeRef);
const querySnap = await getDoc(q);
querySnap.forEach(async (doc) => {
const radnoVrijeme = doc.data().radno_vrijeme;
// Find the index of the hour you want to delete
const index = radnoVrijeme["Mon"].indexOf(hour);
// Remove the hour from the array
radnoVrijeme["Mon"].splice(index, 1);
// Update the document in the collection
console.log(radnoVrijeme);
const radnoVrijemeMap = new Map(Object.entries(radnoVrijeme));
await freeTimeRef.update({ radno_vrijeme: radnoVrijemeMap });
});
} catch (error) {
console.log(error);
}
};
I tried to pass it as JSON stringified object, but it didn't work. I always get this error :
"FirebaseError: Expected type 'ya', but it was: a custom Ia object"
When you are trying to fetch multiple documents using a collection reference or query, then you must use getDocs():
const finishReservation = async () => {
try {
const freeTimeRef = collection(db, `${barber}`);
const q = query(freeTimeRef);
const querySnap = await getDocs(q);
const updates = [];
querySnap.forEach((d) => {
const radnoVrijeme = d.data().radno_vrijeme;
const index = radnoVrijeme["Mon"].indexOf(hour);
radnoVrijeme["Mon"].splice(index, 1);
const radnoVrijemeMap = new Map(Object.entries(radnoVrijeme));
updates.push(updateDoc(d.ref, { radno_vrijeme: radnoVrijemeMap }))
});
await Promise.all(updates);
console.log("Documents updated")
} catch (error) {
console.log(error);
}
};
getDoc() is used to fetch a single document using a document reference.

Check if ipfs data exists

Using the ipfs-http-client I can successfully add data using the below method. The console.log(added) returns an object with the path, cid, and size keys.
However, the console.log(exists) line returns Object [AsyncGenerator] {}.
I would like to be able to check if a data string exists. Is this possible?
import { create as ipfsHttpClient } from 'ipfs-http-client'
const ipfsClient = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0')
const handleData = async (data) => {
const added = await ipfsClient.add(data)
console.log(added)
const exists = await ipfsClient.get(data)
console.log(exists)
}
handleData('hello world')
The get method returns AsyncIterable<Uint8Array> object, which may be what you're printing out. To get each bytes, you will have to loop over it:
const cid = 'QmQ2r6iMNpky5f1m4cnm3Yqw8VSvjuKpTcK1X7dBR1LkJF'
for await (const buf of ipfs.get(cid)) {
// do something with buf
console.log(buf);
}
If all you care about is whether the data exists, you can just call next() method on the iterator and check for null or error.
const exists = (await ipfs.get(cid)).next() !== null

convert key value pair array to JSON [duplicate]

This question already has answers here:
Serializing an object to JSON
(4 answers)
Closed 2 years ago.
i have a function that scans a directory and builds a key,value pair of all folders and their respective files in it.
const listNotes = () => {
const listing = [];
try{
const folders = fs.readdirSync(defaultPath);
folders.forEach((folder) => {
let v = fs.readdirSync(`${defaultPath}/${folder}`);
listing[folder] = v;
});
} catch (err) {
console.log(err);
}
return listing;
};
and this is an output of such scan
[ DailyTask: [ 'Chores.json' , 'Sunday.json'] ]
that is a folder called DailyTask containing 2 files.
How do i convert this structure to JSON.
The problem with your listing variable is that it's an Array. JSON.stringify() doesn't include all the keys in the array, just the order of items, such as listing[0], listing[1]. In your case, you aren't really using listing as an array, you are using is as an object. You can just make it a object, and then when you call JSON.stringify() it will include the keys.
Solution
const listNotes = () => {
const listing = {};
try{
const folders = fs.readdirSync(defaultPath);
folders.forEach((folder) => {
let v = fs.readdirSync(`${defaultPath}/${folder}`);
listing[folder] = v;
});
} catch (err) {
console.log(err);
}
return listing;
//If you want to convert to JSON
console.log(JSON.stringify(listing));
};

ReactJS - JavaScript: Filter function does not work properly

I am building a boat visualizer using AISHub APIs. After inquiring the APIs I am able to obtain a json file with thousands of vessels, but I filter only the vessels I am interested in, and inject them into a table on a webpage. The API gives the following fileds: [NAME, MMSI, LONGITUDE, LATITUDE, others...]. The most important parameters I am using for the filtering are : NAME and MMSI (whereas there could be multiple vessels with same NAME, there cannot be two vessels with the same MMSI number because it is unique).
The problem I have is that the filter function does not seem to have the proper behavior.
In fact it does not filter uniquely for that specific NAME and/or MMSI and I end up having multiple vessels with same NAME and with different MMSI. Also the vessel that should appear, it does not, despite I hard-coded the NAME and MMSI for that specific vessel.
Which is not explainable as I hard-coded those numbers to be specifically filtered.
Below the code I am using for the filtering search:
var express = require('express');
var router = express.Router();
var axios = require('axios');
const NodeCache = require('node-cache');
const myCache = new NodeCache();
let hitCount = 0;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
const mmsiOfInterest = [
'367029520', // ok -> MICHIGAN
'366909730', // ok -> JP BOISSEAU
'367128570', // ok -> DELAWARE BAY
'366744010', // ok -> ATLANTIC SALVOR
// Other MMSI numbers .....
];
const shipNamesOfInterest = [
'MICHIGAN',
'JP BOISSEAU',
'DELAWARE BAY',
'ATLANTIC SALVOR',
// Other NAMES....
]
router.get('/hello', async function(req, res, next) {
const allData = myCache.get('allData');
if (!allData) {
hitCount++;
console.log(`hit ${hitCount} number of times`);
const { data } = await axios.get(
'http://data.aishub.net/ws.php?username=MY_KEY&format=1&output=json&compress=0&latmin=11.42&latmax=58.20&lonmin=-134.09&lonmax=-52.62'
);
const [ metaData, ships ] = data;
console.log(data);
const shipsOfInterest = ships.filter(
(ship) => mmsiOfInterest.includes(ship.MMSI) || shipNamesOfInterest.includes(ship.NAME)
);
myCache.set('allData', shipsOfInterest, 70);
res.send(data);
return;
}
console.log('this is the data:', allData);
res.send(allData);
});
module.exports = router;
Also below a typical JSON response from the API:
{"MMSI":225342000,"TIME":"2020-01-26 01:45:48 GMT","LONGITUDE":1.43912,"LATITUDE":38.91523,"COG":339.9,"SOG":0,"HEADING":297,"ROT":0,"NAVSTAT":0,"IMO":9822449,"NAME":"ILLETAS JET","CALLSIGN":"EAVX","TYPE":40,"A":4,"B":25,"C":4,"D":4,"DRAUGHT":0,"DEST":"IBIZA","ETA":"00-00 00:00"}
What I have done so far:
1) I tried different combination with the filter function and I tried to filter by MMSI, which is supposed to be unique for each vessel, but still I end up with vessels with same NAME and different MMSI (despite I hard-coded the MMSI...I don't understand):
const shipsOfInterest = ships.filter(
(ship) => mmsiOfInterest.includes(ship.MMSI)
);
After I tried filtering by NAME, but that does not work either:
const shipsOfInterest = ships.filter(
(ship) => shipNamesOfInterest.includes(ship.NAME)
);
EDIT 2
router.get('/hello', async function(req, res, next) {
//
const allData = myCache.get('allData');
if (!allData) {
hitCount++;
console.log(`hit ${hitCount} number of times`);
const { data } = await axios.get(
'http://data.aishub.net/ws.php?username=KEY&format=1&output=json&compress=0&latmin=11.42&latmax=58.20&lonmin=-134.09&lonmax=-52.62'
);
// console.log(data);
const { metaData, ships } = data;
const set = new Set();
const shipsOfInterest = ships.filter((ship) => {
if (set.has(ship.MMSI)) return false;
set.add(ship.MMSI);
return true;
});
myCache.set('allData', shipsOfInterest, 70);
res.send(data);
return;
}
console.log('this is the data:', allData);
res.send(allData);
});
module.exports = router;
Below the error:
I don't know if the filter function can get a better result if organized in a different way. I thought that this could have been a very good way to organize the search and don't understand what it does not work.
Thanks for pointing to the right direction for solving this issue.
In the end of if statement you do res.send(data), which is basically the data you received from the API. Instead, you need to res.send(shipsOfInterest); Also, change the format of mmsiOfInterest list from strings to numbers, because you receive numbers from the API.
I guess you made mistake while using the shorthand assignment. Use {} instead of [].
Instead of:
const [ metaData, ships ] = data;
try:
const { metaData, ships } = data;
So, as far as I understand you the filtered list to contain the records with unique MMSI value. So, what you need to do is:
const uniqueMMSI = new Set();
const shipsOfInterest = ships.filter(
(ship) => {
if (set.has(ship.MMSI)) return false;
set.add(ship.MMSI);
return true;
}
);
I hope I understood your question :)
It looks like MMSI is coming in as a numeric value, while your comparison array is holding strings. How about using an array of integers for your comparison?
const mmsiOfInterest = [
367029520,
366909730,
367128570,
366744010,
// Other MMSI numbers .....
];

How to return an array of children from firebase in React-Native

My Firebase data base contains JSON objects, each with the same parameters as seen below. Firebase data
I want to get an array that has each objects country. So if I have 4,000 objects I want to get an array of 4,000 strings all containing a country.
Right now I can get the console to log all the 4,000 objects into an array using the code below.
componentWillMount() {
this.fetchData();
}
fetchData = async () => {
var data1 = [];
var fireBaseResponse = firebase.database().ref();
fireBaseResponse.once('value').then(snapshot => {
snapshot.forEach(item => {
var temp = item.val();
data1.push(temp);
return false;
});
console.log(data1);
});
}
But when I try doing
var fireBaseResponse = firebase.database().ref().child('country');
I get an array of nothing.
Any help would be great.
As mentioned in the comments, you can create a new temp object containing just country before pushing it into your array.
snapshot.forEach(item => {
var temp = { country: item.val().country };
data1.push(temp);
return false;
});

Categories