Mongoose Query FindOne with array - javascript

So i want to verify if a value is inside the collection. I've managed to do it using .map. My code looks like this (the field is nested):
const loopFields = [
"nested.field1",
"nested.field2",
"nested.field3",
"nested.field4"
];
async function getField() {
const field = loopFields.map(async (fld, idx) => {
const result = await Field.findOne({ [fld]: req.body.field });
if (result) {
return fld;
}
});
const isFound = await Promise.all(field);
for (i = 0; i < loopFields.length; i++) {
if (isFound[i] !== undefined) {
return true;
}
}
}
const isValid = await getField();
if (!isValid) {
return res.status(400).send("Field not found");
}
The code does work but i'm looking for a way to reffactore it.

build an $or clause dynamically and pass it to the find method like so:
var loopFields = [
"nested.field1",
"nested.field2",
"nested.field3",
"nested.field4"
];
var fields = loopFields.map(field => {
var x = {};
x[field] = req.body.field;
return x;
})
db.collection.find({ $or: fields });

Related

Javascript: How to update IndexedDB?

I'm trying to create a chrome extension, but I am having some trouble updating my DB.
In the code below I am using index.get to the the object that contains a certain value. If such an object doesn't exist I will create a new one, which works just fine.
But if the DB contains an object with the specified value, I want to append a new object to an array (allMessages) that is inside the object I searched for. The details doesn't really matter in this case.
What is important is to find out if the way I'm adding this new obj to the array (allMessages) is a valid way of updating the database.
records.forEach((person) => {
console.log("here1");
const index = objectStore.index("urlKeyValue");
let search = index.get(person.urlKeyValue);
search.onsuccess = function (event) {
if (search.result === undefined) {
// no record with that key
let request = objectStore.add(person);
request.onsuccess = function () {
console.log("Added: ", person);
};
} else {
// here I'm iterating an array that is inside the obj I searched for,
// and then checking if the key for that array matches **theUserId**
for (userObj of event.target.result.allMessages) {
if (theUserId == Object.keys(userObj)) {
// is this part correct. Is it possible to update the DB this way?
let objToAdd1 = {
time: person.allMessages[0][theUserId][0].time,
msg: person.allMessages[0][theUserId][0].msg,
};
let currentObj = userObj[theUserId];
let updatedObj = currentObj.push(objToAdd1);
}
}
)}
Using objectStore.openCursor you can update only part of the record.
The following updates only book prices.
const transaction = db.transaction("books", "readwrite");
const objectStore = transaction.objectStore("books");
records = [{ id: "kimetu", price: 600 }];
records.forEach((book) => {
const index = objectStore.index("id");
const search = index.get(book.id);
search.onsuccess = () => {
if (search.result === undefined) {
const request = objectStore.add(book);
request.onsuccess = () => {
console.log("Added: ", book);
};
} else {
const request = objectStore.openCursor(IDBKeyRange.only(book.id));
request.onsuccess = () => {
const cursor = request.result;
if (cursor) {
cursor.value.price = 1000;
const updateRequest = cursor.update(cursor.value);
updateRequest.onsuccess = () => {
console.log("Updated: ", cursor.value.price);
};
cursor.continue();
}
};
}
}
});

Node.js How to retrieve data from http.get response

I am doing some practice in node.js. In this exercise I been asked to find a country name through a GET Http Request to an endpoint passing a page integer as a parameter.
Where the important response structs are these {page, total_pages, data}.
page is the current page,
total_pages is the last page,
data is an array of 10 country object.
In getCountryName func I am able to retrieve the right answer only if the answer is on the 1st page, the 1 iteration of the loop. So, why the loop only happens once?
Aditional, I wanted to retrieve the total_pages to replace the hardcode '25' value but I do not figure it out how to return it along with the search.
Any hint you wanna give me? The whole problem is in getCountryCode func.
'use strict';
const { Console } = require('console');
const https = require('https');
function makeRequest(page){
return new Promise(resolve => {
let obj='';
https.get('https://jsonmock.hackerrank.com/api/countries?page='+page, res => {
let data ='';
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
obj=JSON.parse(data);
resolve(obj);
});
});
});
}
async function getCountryName(code) {
var res = '';
var pages = 25;
var i = 1;
while(i <= pages && res == ''){
console.log(i);
res = makeRequest(i)
.then(data => {
let f = ''
let p = data['total_pages'];
let search = data['data'].find(o => o.alpha3Code === code);
f = search != null ? search['name'] : f;
return f;
});
i++;
}
return res;
}
async function main() {
const name = await getCountryName('ARG');
console.log(`${name}\n`);
}
main();
Without modifying your code too much, this is how you do it:
'use strict';
const { Console } = require('console');
const https = require('https');
function makeRequest(page){
return new Promise(resolve => {
let obj='';
https.get('https://jsonmock.hackerrank.com/api/countries?page='+page, res => {
let data ='';
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
obj=JSON.parse(data);
resolve(obj);
});
});
});
}
async function getCountryName(code) {
const pages = 25;
var i = 1;
let f = null
while(i <= pages && f === null){
console.log(i);
const data = await makeRequest(i) // put in try/catch
const p = data['total_pages'];
const search = data['data'].find(o => o.alpha3Code === code);
f = search !== null ? search['name'] : null;
i++;
}
return res;
}
async function main() {
const name = await getCountryName('ARG');
console.log(`${name}\n`);
}
main();

angularjs combine two Trello api and assign it to $rootScope variable

Hello there I have a function that will combine two API from Trello.
if I console.log, it will give the result correctly:
but I Would like to assign it's value to a $rootScope so I can use it to the component.
my .run() code:
angular.module('workTrello', [
'ngRoute'
])
.config()
.run(function($rootScope){
async function trelloCards() {
let response = await fetch(`https://api.trello.com//1/boards/5ba38efef50b8979566922d0/cards?key=${key}&token=${token}`);
return await response.json();
}
async function trelloLists() {
let response = await fetch(`https://api.trello.com/1/boards/5ba38efef50b8979566922d0/lists?key=${key}&token=${token}`)
return await response.json();
}
async function bindWorkInfo() {
const cards = await trelloCards();
const lists = await trelloLists();
let trelloWorkData = [];
for (let i = 0; i < lists.length; i++) {
const list = lists[i];
list.name = list.name.substr(0,list.name.indexOf(' '))
let listWithCard = [];
for (let x = 0; x < cards.length; x++) {
const card = cards[x];
if (card.idList == list.id) {
try { /** 8-12+14-16 = 6*/
card.name = Math.abs(eval(card.name));
listWithCard.push({
id:list.id, date:list.name, idCard:card.id,
time:card.name, task:card.badges.checkItemsChecked,
idMember:card.idMembers[0]
});
} catch (error) {}
}
}
trelloWorkData.push(listWithCard);
}
console.log(trelloWorkData)
return trelloWorkData;
}
bindWorkInfo().then((res) => $rootScope.workedInfo = res);
}
this my attempt :
bindWorkInfo().then((res) => $rootScope.workedInfo = res);
but when I access $rootScope.workedInfo from the component it will return as undefined.
anyone know the correct way of assigning it to $rootScope ?
you have to return a promise to make the function thennable. change the following return code
return trelloWorkData;
to
return Promise.resolve(trelloWorkData);
and try.

Confirmed populated array of objects returns empty

I have a method that is failing when returning an array of objects. As mentioned in the title - the array is confirmed to be populated but is empty in the response.
Here is the full flow:
The Url:
http://localhost:53000/api/v1/landmarks?lat=40.76959&lng=-73.95136&radius=160
Is routed to the corresponding index:
api.route('/api/v1/landmarks').get(Landmark.list);
The Index Calls a Service:
exports.list = (req, res) => {
const landmark = new LandmarkService();
landmark.getLandmarks(req)
.then(landmarks => {
var response = new Object();
response.startindex = req.query.page;
response.limit = req.query.per_page;
response.landmarks = landmarks;
res.json(response);
})
.catch(err => {
logger.error(err);
res.status(422).send(err.errors);
});
};
The Service Method Uses a Data Access Class to Return the Promise
getLandmarks(req) {
const params = req.params || {};
const query = req.query || {};
const page = parseInt(query.page, 10) || 1;
const perPage = parseInt(query.per_page, 10);
const userLatitude = parseFloat(query.lat);
const userLongitude = parseFloat(query.lng);
const userRadius = parseFloat(query.radius) || 10;
const utils = new Utils();
const data = new DataService();
const landmarkProperties = ['key','building','street','category','closing',
'email','name','opening','phone','postal','timestamp','type','web'];
return data.db_GetAllByLocation(landmarksRef, landmarkLocationsRef,
landmarkProperties, userLatitude, userLongitude, userRadius);
} // getLandmarks
However, the response is always empty.
I am building an array in the called method and populating it with JSON objects. That is what is supposed to be sent back in the response. I can confirm that the attributes array is correctly populated before I hit the return statement. I can log it to the console. I can also send back a test array filled with stub values successfully.
I have a feeling it is how I am setting things up inside the Promise?
Data Access Method That Should Return Array of Objects:
db_GetAllByLocation(ref, ref_locations, properties, user_latitude, user_longitude, user_radius)
{
const landmarkGeoFire = new GeoFire(ref_locations);
var geoQuery = landmarkGeoFire.query({
center: [user_latitude, user_longitude],
radius: user_radius
});
var locations = [];
var onKeyEnteredRegistration = geoQuery.on("key_entered", function (key, coordinates, distance) {
var location = {};
location.key = key;
location.latitude = coordinates[0];
location.longitude = coordinates[1];
location.distance = distance;
locations.push(location);
});
var attributes = [];
var onReadyRegistration = geoQuery.on("ready", function() {
ref.on('value', function (refsSnap) {
refsSnap.forEach((refSnap) => {
var list = refSnap;
locations.forEach(function(locationSnap)
{
//console.log(refSnap.key, '==', locationSnap.key);
if (refSnap.key == locationSnap.key)
{
var attribute = {};
for(var i=0; i<=properties.length-1; i++)
{
if(properties[i] == 'key') {
attribute[properties[i]] = refSnap.key;
continue;
}
attribute[properties[i]] = list.child(properties[i]).val();
}
attribute['latitude'] = locationSnap.latitude;
attribute['longitude'] = locationSnap.longitude;
attribute['distance'] = locationSnap.distance;
attributes.push(attribute);
} // refSnap.key == locationSnap.key
}); // locations.forEach
}); // refsSnap.forEach
return Promise.resolve(attributes); <-- does not resolve (throws 'cannot read property .then')
//geoQuery.cancel();
}); // ref.on
}); // onreadyregistration
return Promise.resolve(attributes); <-- comes back empty
}
It seems that data.db_GetAllByLocation is an asynchronous function, therefore the call resolve(landmarks); is getting called before the execution of the async function is finished. If the data.db_GetAllByLocation returns a promise then call the resolve(landmarks) inside the promise.
data.db_GetAllByLocation().then(function() {
resolve();
})
Also try the following modified db_GetAllByLocation()
db_GetAllByLocation(ref, ref_locations, properties, user_latitude, user_longitude, user_radius)
{
return new Promise(function(resolve, reject){
const landmarkGeoFire = new GeoFire(ref_locations);
var geoQuery = landmarkGeoFire.query({
center: [user_latitude, user_longitude],
radius: user_radius
});
var locations = [{}];
var onKeyEnteredRegistration = geoQuery.on("key_entered", function (key, coordinates, distance) {
var location = {};
location.key = key;
location.latitude = coordinates[0];
location.longitude = coordinates[1];
location.distance = distance;
locations.push(location);
});
var attributes = [{}];
var onReadyRegistration = geoQuery.on("ready", function() {
ref.on('value', function (refsSnap) {
refsSnap.forEach((refSnap) => {
var list = refSnap;
locations.forEach(function(locationSnap)
{
if (refSnap.key == locationSnap.key)
{
var attribute = {};
for(var i=0; i<=properties.length-1; i++)
{
if(properties[i] == 'key') {
attribute[properties[i]] = refSnap.key;
continue;
}
attribute[properties[i]] = list.child(properties[i]).val();
}
attribute['latitude'] = locationSnap.latitude;
attribute['longitude'] = locationSnap.longitude;
attribute['distance'] = locationSnap.distance;
attributes.push(attribute);
} // refSnap.key == locationSnap.key
}); // locations.forEach
}); // refsSnap.forEach
// return JSON.stringify(attributes);
return resolve(attributes);
}); // ref.on
}); // onreadyregistration
});
}
OK, I sorted this by removing all my code and writing some test logic (I should have done this before I posted my question).
The below flow works for me, and, applied back to my code, gave me the results I was looking for. No need to re-post the code, but maybe the below flow will be helpful to somebody.
route
api.route('/api/v1/landmarks').get(Landmark.test);
index
exports.test = (req, res) => {
const landmark = new LandmarkService();
landmark.getLandmarksTest(req)
.then(landmarks => {
var final = {};
final.attr1 = 'attr1';
final.attr2 = 'attr2';
final.landmarks = landmarks;
res.json(final);
})
.catch(err => {
logger.error(err);
res.status(422).send(err.errors);
});
};
service method
getLandmarksTest(req)
{
const data = new DataService();
data.db_PromiseTest().then(results => {
return Promise.resolve(results);
}).catch(err => {
return Promise.reject(err.errors);
});
}
data layer method
db_PromiseTest()
{
var stub = {
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
};
return Promise.resolve(stub);
}

Resolve returns empty array when console.log returns array with values

In getNestedFlags I'm adding values to finalJson array.
Then after console.log I can see entire finalJson array with values but resolve returns an empty array. Do you know how to achive the same result in resolve as in console.log?
getScheduledFlags: (idTc, idScheduled) => {
return new Promise((resolve, reject) => {
var getNestedFlags = (array1, array2, res) => {
array1.forEach(item => {
var childrenItems = res.filter(item1 => item1.id_parent == item.id)
if(childrenItems.length > 1){
var childrens = []
getNestedFlags(childrenItems, childrens, res)
array2[item.name] = childrens
} else {
array2[item.name] = item.value
}
})
}
_tc.get(idTc).then(result => {
var flags = result.flags
var bases = result.bases
_featureFlags.getAll().then(allFlags => {
tcScheduled= _featureFlags.getFinalTcFlags(result)
res = _this.replaceFlags(allFlags, tcScheduled.flags)
parentFlags = res.filter(item => item.id_parent == 0)
var finalJson = []
getNestedFlags(parentFlags, finalJson, res)
console.log(finalJson)
resolve(finalJson)
})
})
})
},
The code which you have posted must work as array is passed by reference rather than value in javascript. Check both the console.log() in the code before and after the call to resolve() function.
var finalJson = []
var parentFlags ='';
var res ='';
getNestedFlags(parentFlags, finalJson, res);
console.log(finalJson);
resolve(finalJson);
console.log(finalJson);
function getNestedFlags(parentFlags, finalJson, res){
finalJson.push(1);
finalJson.push(2);
finalJson.push(3);
}
function resolve(finalJson){
finalJson.push(4);
finalJson.push(5);
}
Initializing array by [] was my problem.
Now with {} everything is fine.

Categories