Querying data from Firebase collection - javascript

I have been working in the LAMP stack for years and am struggling to wrap my head around advanced querying with Firebase and NoSQL databases. I would like to return 5 random documents from a collection. Below is the VueJS code written thus far:
Here is the data object that I have created:
data () {
return {
courseIds: [],
}
}
Here is my created lifecycle hook where I'm querying the Firebase NoSQL database:
created() {
// fetch data from firestore
database.collection('courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courseIds.push(course.id)
})
})
}
Because I'm looking to randomize the data returned, I have added the beforeMount lifecycle hook which calls a Fisher-Yates shuffle method. The plan was to shuffle the returned data and then return only the first 5 documents:
beforeMount() {
this.courseIds = this.shuffle(this.courseIds)
}
And the method:
methods: {
shuffle: function(array) {
var m = array.length, t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
}
I'm a slow learner, so more than likely this is a numbskull approach to the problem. My present issue is that Firebase is returning the Ids as an object rather than an array so my shuffle method isn't working as anticipated. See the console.log() below:
[__ob__: Observer]
0: "0HnqJ8zZg1Rs3D4qod4l"
1: "1gZmoUpCOSDeLsYMDi4v"
2: "JrJj3a84qKTD72ncvGXd"
3: "LWMbY98m3sKLrHNDSUkW"
4: "SUn1kxHzMo7fu5urpNB5"
5: "kQRWQIj0mFXIWVJcaouY"
length: 6
__ob__: Observer {value: Array(6), dep: Dep, vmCount: 0}
__proto__: Array
Does anybody have a better approach to this functionality, or a good way to convert the courseIds into an array to be shuffled?

What happens if you do a bit differently, as follows:
created() {
// fetch data from firestore
database.collection('courses').get()
.then(snapshot => {
let courseIdsArray = [];
snapshot.forEach(doc => {
courseIdsArray.push(doc.id);
});
this.courseIds = courseIdsArray;
});
}

Related

Filtering data after fetching in React

I need to make a list of objects based on combined data from 2 arrays, one comes from a localStorage and the second one from Django backend. First of all objects from localStorage are displayed by showCart() function
export const showCart = () => {
if (typeof window !== undefined) {
if (localStorage.getItem("cart")) {
return JSON.parse(localStorage.getItem("cart"));
};
};
};
it returns data in this format: FE: { id: 1, amount: 7, size: "L", product: 1 }. product is the Foreign Key needed to match data from other array.
The second array comes form a backend and it is feched by getAllProducts() function
export const getAllProducts = () => {
return fetch(`${url}/products/`, {method: "GET"})
.then((response) => {
return response.json();
})
.catch((error) => console.log(error))
};
It returns data in this format: FE { name: "Red", id: 3, price: 33, image:"some-url"}
​​
Now I need to create another list of objects by merging then by product of an object in first array with id of an object from the second one. The objects in the third array need to contain amount and size from first array as well as name, price and image from the second one. In the end I want to store it in useState().
This is what I came up with, I guess my code stops working arter first for loop:
const [cart, setCart] = useState([]);
const CheckAnonymousCart = () => {
getAllProducts()
.then((data) => {
const localCart = showCart();
var products = [];
for (let i = 0; i < localCart.lenght; i++) {
for (let y = 0; y < data.lenght; y++) {
if (localCart[i].product === data[y].id) {
console.log(localCart[i].product, data[y].id)
const item = {
name: data[y].name,
price: data[y].price,
image: data[y].image,
amount: localCart[i].amount,
size: localCart[i].size,
}
products.push(item)
break;
}
}
}
setCart(products);
})
.catch((error) => console.log(error))
};
​​Any thoughts?
In addition to Jacob's comment, you probably want to avoid FETCH'ing all products from the DB, because it requires more DB resources, most of the info is not required, and it makes the for-loop take longer to JOIN both lists.
Ideally, you would use a parameterized query like so:
return fetch(`${url}/products/?id=1&id=2&id=3`, {method: "GET"})
Where ?id=1&id=2&id=3 are a subset of the product IDs that you're retrieving.
Note: You will also want to sanitize/validate the product IDs in localStorage, because the data can be modified by the end-user, which is a potential attack vector by malicious users.
The problem could simply be the typo from the for loop conditions, but you can also accomplish this more succinctly using the JS ES6 methods:
const products = localCart.map(item => {
const match = data.find(x => x.id === item.product);
return {
amount,
size,
name: match?.name,
price: match?.price,
image: match?.image
}
});

How do I pull a nested object out of an array with an api request returned json?

I have an API that I am calling to return a query. This query's format cannot be changed to be easier to manipulate. It has a nested array within it that I need to associate with the data from the higher levels.
Specifically, I am trying to pull the higher level id field and and the "value" field within "column_values" and associate them with one another preferably within a new array. I feel like the answer is here but I just can't grasp how to pull the data in the correct format and associate it together. Most of the comment lines can probably be ignored, they are my other attempts at making the syntax work correctly. Sorry about the mess. I'm really new to this.
const axios = require('axios')
const body = {
query: ` query {boards(ids:307027197) {name, items {name id column_values(ids:lockbox_) {title id value text}}}} `,
}
console.log("Requesting Query....");
function getApi (callback){
setTimeout(function() {axios.post(`https://api.monday.com/v2`, body, {
headers: {
MY_API_KEY_DATA
},
})
.catch(err => {
console.error(err.data)
})
.then(res => {
var queried = res
var array = queried.data.data.boards[0].items
//console.log(queried)
//console.log(array)
console.log(array.length)
//console.log("Total Items:", array.length)
var i;
for (i = 0; i < array.length; i++){
callback(queried.data.data.boards[0].items)
//callback([(queried.data.data.boards[0].items[i].column_values[0])])
}
}, 0);
})
};
getApi(callback => {
console.log(callback)
//console.log(parsed)
//output for above
//{"name":"address","id":"1234","column_values":
//[{"title":"Lockbox#","id":"lockbox_","value":"\"31368720\"","text":"31368720"}]}
//console.log(JSON.parse(parsed))
//output for above
//[
// {
// name: 'address',
// id: '353428429',
// column_values: [ [Object] ]
// }
//]
});
setTimeout(function() {
console.log("Query Returned")},1000);
From your data, column_values is an array with objects in it. For an array, you will have to access it with the key. For your case, if your data is like
var data = {
"name":"address",
"id":"1234",
"column_values": [{"title":"Lockbox#","id":"lockbox_","value":"\"31368720\"","text":"31368720"}]
}
You can access the id of column_values as data.column_values[0].id

Can arbitrary objects be made reactive in Vuex?

I am looking for ways to optimize sorting normalized objects by a relationship. Let's pretend that one has an app that needs to sort
I have a Vuex store that contains many normalized objects, like so:
state: {
worms: {
3: { id: 3, name: 'Slurms McKenzie', measurements: [1, 6, 9] },
4: { id: 4, name: 'Memory worm', measurements: [3, 4, 12] },
6: { id: 6, name: 'Alaskan Bull Worm', measurements: [5, 7, 14]},
...
},
measurements: {
1: { id: 1, length: 5.2, timestamp: ...},
2: { id: 2, length: 3.4, timestamp: ...},
3: { id: 3, length: 5.4, timestamp: ...},
...
},
};
Say I need to sort my worms on the timestamp that they reached their highest length. Being steeped in Vue's reactivity, I would love to be able to defined a getter on each worm, like this:
const getters = {
longestLength: {
get() { return $store.getters
.measurements(this.measurements)
.sort(...)[0] },
},
timestampForLongest: {
get() { return this.longestLength.timestamp }
}
worm.extend(getters);
I could then easily and quickly sort on timestampForLongest assuming the value is cached.
I have a great entry point to call this extend (or whatever it ends up being called), but I have a few challenges.
The way I handle this now is by calculating a denormalized map and then sorting based on this. The latency is ~700ms on my 8th gen Intel processor in Chrome, which I'd really like to cut down on.
I don't know how to invoke Vue's reactivity system manually. I believe that I need to define getters that call something like measurement.__ob__.dep.depend() but I haven't wrapped my head around it.
The API to achieve this may be private and subject to change. Is Vue just too slow to handle 800+ rows?
I don't know how to keep the Vuex store ($store) in scope for the getters. I could probably use arrow functions, so I'm not as worried about this.
Can I calculate and cache values on demand in plain javascript objects using Vue?
Hopefully this is somewhere close to what you had in mind.
If I've understood correctly, your intent was to create 'computed properties' (or getters of some kind) called longestLength and timestampForLongest on each worm. These would derive their values based on the measurements in the state.
I've attempted to do this by making each worm a Vue instance. Obviously there's a lot of other functionality that a Vue instance provides, such as rendering, that isn't needed in this case. In Vue 2 there isn't any way to single out just the bits you need. Rumour has it Vue 3 may be more modular in this regard. The only bits we need are observable data (which could be implemented using Vue.observable) and computed properties (which are only available via a Vue instance). For what it's worth, this is how Vuex works behind the scenes, creating a separate Vue instance and plugging into the data, computed, etc..
While the code below looks long, much of it is concerned with generating suitable test data. I initially generate data with measurements nested inside the worms and then pull it out to the format you've specified inside my mutation. Each instance inside worms is converted to a Vue instance before it is added to the state.
I've added // This bit is important comments to particularly important sections to make it easier to pick them out of the noise.
// This bit is important
const Worm = Vue.extend({
computed: {
longestLength () {
let longest = null
for (const id of this.measurements) {
const measurement = store.state.measurements[id]
if (!longest || measurement.length > longest.length) {
longest = measurement
}
}
return longest
},
timestampForLongest () {
return this.longestLength.timestamp
}
}
})
const state = {
worms: {},
measurements: {}
};
const mutations = {
populate (state, worms) {
const wormState = {}
const measurementsState = {}
let measurementId = 0
for (const worm of worms) {
const measurementIds = []
for (const measurement of worm.measurements) {
measurementId++
measurementIds.push(measurementId)
measurementsState[measurementId] = {id: measurementId, ...measurement}
}
// This bit is important
wormState[worm.id] = new Worm({
data: {...worm, measurements: measurementIds}
})
}
state.worms = wormState
state.measurements = measurementsState
}
};
const getters = {
// This bit is important
sortedWorms (state) {
return Object.values(state.worms).sort((wormA, wormB) => wormA.timestampForLongest - wormB.timestampForLongest)
}
};
const actions = {
populateWorms ({commit}) {
const worms = []
for (let wIndex = 0; wIndex < 800; ++wIndex) {
const measurements = []
for (let mIndex = 0; mIndex < 3; ++mIndex) {
measurements.push({
length: Math.round(Math.random() * 100) / 10,
timestamp: Math.round(Math.random() * 1e6)
})
}
worms.push({
measurements,
name: 'Worm ' + wIndex,
id: wIndex
})
}
commit('populate', worms)
}
}
const store = new Vuex.Store({
state,
mutations,
getters,
actions
})
new Vue({
el: '#app',
store,
computed: {
sortedWorms () {
return this.$store.getters.sortedWorms
}
},
methods: {
go () {
this.$store.dispatch('populateWorms')
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuex#3.1.1/dist/vuex.js"></script>
<div id="app">
<button #click="go">Go</button>
<div v-for="worm in sortedWorms">
{{ worm.name }} - {{ worm.longestLength }}
</div>
</div>
Whether or not this is actually a good way to implement all of this given your underlying requirement of optimum sorting I'm not so sure. However, it seemed as close as I could get to your intent of implementing computed properties on each worm.
I would suggest you a totally different approach:
1. Avoid sorting by any means
2. Instead, have properties corresponding to max_length and max_time on each worm object and update them (max properties) whenever a new observation is posted (or recorded) for that worm
This way, you can avoid sorting each time.
The code you provided has syntax errors, they had to be corrected:
const states = {
worms: {
3: {
id: 3,
name: 'Slurms McKenzie',
measurements: [1, 6, 9]
},
4: {
id: 4,
name: 'Memory worm',
measurements: [3, 4, 12]
},
6: {
id: 6,
name: 'Alaskan Bull Worm',
measurements: [5, 7, 14]
}
},
measurements: {
1: {
id: 1,
length: 5.2,
timestamp: 'ts1'
},
2: {
id: 2,
length: 3.4,
timestamp: 'ts2'
},
3: {
id: 3,
length: 5.4,
timestamp: 'ts3'
},
}
}
const store = new Vuex.Store({
state: states,
getters: {
getWorms: state => {
return state.worms
},
getLongestLengthByMeasurementId: state => ids => {
const mapped = ids.map(id => {
const measurement = state.measurements[id]
if (measurement) {
return {
length: measurement.length || 0,
timestamp: measurement.timestamp || 0
}
} else {
return {
length: 0,
timestamp: 0
}
}
})
return mapped.find(item => item.length === Math.max.apply(null, mapped.map(item => item.length))).timestamp
}
},
mutations: {
// setting timestamp in store.state.worms[wormId]
setLongestLength(state, wormId) {
if (state.worms[wormId] && typeof state.worms[wormId].timestamp !== 'undefined') {
// update the timestamp
} else {
// get and set the timestamp
const ts = store.getters.getLongestLengthByMeasurementId(state.worms[wormId].measurements)
Vue.set(state.worms[wormId], 'timestamp', ts)
}
},
},
actions: {
// set timestamp worm by worm
setLongestLength({
commit
}, wormId) {
Object.keys(store.getters.getWorms).forEach(key =>
commit('setLongestLength', parseInt(key, 10))
)
}
}
})
const app = new Vue({
store,
el: '#app',
mounted() {
store.dispatch('setLongestLength')
console.log('worms', store.state.worms)
}
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
<div v-for="worm in $store.state.worms">Timestamp by worm (ID {{worm.id}}): {{worm.timestamp}}</div>
</div>
You only need to add get: in your getter if you also use a set:.
Usually when I make a Vue application with a lot of data such as yours, I'll do something like this:
const vm = new Vue({
data() {
return {
worms: [
{id: 1,name: "Slurms McKenzie",measurements: [1, 6, 9]},
{id: 2,name: "Memory worm",measurements: [3, 4, 12]},
{id: 3,name: "Alaskan Bull Worm",measurements: [5, 7, 14]}
],
measurements: [
{id: 1,length: 5.2,timestamp: 123},
{id: 2,length: 3.4,timestamp: 456},
{id: 3,length: 5.4,timestamp: 789}
]
};
},
computed: {
sortedByLength() {
return [...this.measurements]
.sort((a, b) => a.length - b.length)
.map(measurement => measurement.id)
.map(id => this.worms.find(worm => worm.id === id));
},
timestampForLongest() {
return this.sortedByLength[0].timestamp;
}
}
});
Vue will update computed properties that change, and cache them otherwise. All you need to do is convert this into state/getters for Vuex and the principles are the same.
Storing them as arrays is much easier to handle than as objects. If you must use objects, you could probably use the lodash library to help you sort without it being obnoxious.
Probably, this might help. I don't know the whole structure of your project but I tried to recreated here and this is one approach.
You've defined a state that contains worms and measurements lists. Each worm has a measurement list of indexes, which I suppose it is related with the measurements list.
Now state should be defined inside of the your Vuex store. Now, your store will have four main elements which includes: state, getters, actions, and mutations.
So the state, in essence, can be viewed as a single source of truth for the entire application. But how can our components and routes access the data stored in our state? Well, the getters will return the data from our store back to our components, in this case we want to get the sortedByTSDec and sortedByTSAsc methods.
So, now you have figured out how to get data from the state, let’s see how we can set data into our state. You must be think I can define setters, right? Well, no, Vuex "setters" are named slightly different. You should define a mutation to set data into your state.
Finally, actions are similar to mutations, but instead of mutating the state directly they commit a mutation. Confused? Just, think about actions like asynchronous functions while mutations are synchronous.
In this example, I don't know where the worms data is being generation it can be from another server, a database, and so on. So the generateData action will request and wait for the data and when the data is ready will call the populate mutation to populate the state.
So what about the Worn class?
Here is where the magic happens. The Vue.extend() method create a subclass of the base Vue constructor. But why? Because this subclass has a data option. When we set this value in the populate mutation with the data of a generated worn. In other words the state.worms contains a list of Worn objects.
Also, we declare the computed properties to calculate the longestLength and timestampForLongest with the data of the instance.
Now if you want to sort the worms list by the timestamp of its longest length then first we need to calculate the longest length, then we use the .sort() method. This method by default sorts values as strings. Therefore, we need to provide a compare function The purpose of the compare function is to define an alternative sort order. This function should return a negative, zero, or positive value, depending on the arguments. In this case we used b.timestampForLongest - a.timestampForLongest for decreasing order, but you can use a.timestampForLongest - b.timestampForLongest for ascending order.
Here is a basic snippet:
const randomDate = function (start, end) {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).getTime()/1000;
};
const Worm = Vue.extend({
computed: {
longestLength() {
let longest;
for (const id of this.measurements) {
const measurement = store.state.measurements[id];
if (!longest || measurement.length > longest.length) {
longest = measurement;
}
}
return longest;
},
timestampForLongest() {
return this.longestLength.timestamp
},
},
});
const store = new Vuex.Store({
state: {
worms: {},
measurements: {},
},
actions: {
generateData({commit}) {
const worms = [];
for (let w = 0; w < 800; ++w) {
const measurements = []
for (let m = 0; m < 3; ++m) {
measurements.push({
length: Math.round(Math.random() * 100) / 10,
timestamp: randomDate(new Date(2018, 1, 1), new Date()),
});
}
worms.push({
id: w,
name: 'Worm Name ' + w,
measurements,
});
}
commit('populate', worms)
}
},
mutations: {
populate(state, worms) {
const wormList = {};
const measurementList = {};
let measurementId = 0;
for (let worm of worms) {
const measurementIds = [];
for (let measurement of worm.measurements) {
measurementId++
measurementIds.push(measurementId)
measurementList[measurementId] = {
id: measurementId,
...measurement,
}
}
wormList[worm.id] = new Worm({
data: {
...worm,
measurements: measurementIds,
}
});
}
state.worms = wormList;
state.measurements = measurementList;
}
},
getters: {
sortedByTSDec(state) {
return Object.values(state.worms).sort((a, b) => b.timestampForLongest - a.timestampForLongest);
},
sortedByTSAsc(state) {
return Object.values(state.worms).sort((a, b) => a.timestampForLongest - b.timestampForLongest);
},
},
});
const app = new Vue({
el: '#app',
store,
computed: {
sortedState() {
return this.$store.getters.sortedByTSDec;
}
},
methods: {
calculate() {
this.$store.dispatch('generateData');
},
timestamp2Date(ts) {
let newDate = new Date();
newDate.setTime(ts * 1000);
return newDate.toUTCString();
}
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.1/vuex.min.js"></script>
<div id="app">
<button v-on:click="calculate">Get the Longest</button>
<div v-for="worm in sortedState">
{{ worm.name }} has its longest length of {{ worm.longestLength.length }}cm at {{ timestamp2Date(worm.longestLength.timestamp) }}
</div>
</div>

How can I return an object from a recursive function upon completion only?

I am calling a recursive function that is returning an object, the object is being returned on each iteration.
I wish to only return an object once the recursive operation has completed. rather than on each iteration.
async fetchRecipe(recipe: any) {
console.log("fetchRecipe");
// Start with a root recipe
let rootRecipe: Recipe = {
id: recipe.id,
name: recipe.name,
ingredients: [],
childRecipes: []
}
// Kick off recursive function
let result = await this.recursivelyBuildRecipe(rootRecipe);
console.log("Fetch Recipe returned");
return result
}
async recursivelyBuildRecipe(recipe: Recipe) {
// fetches using the API
console.log("recursivelyBuildRecipe");
this.fetchChildren('http:///recipes/get_children', 'id=' + recipe.id)
.then(async x => {
await x.data.children.forEach((async(child: { type: any; ItemId: string; name: string; }) => {
switch (child.type) {
case 'ingredient':
// if ingredient
let ingredient: Ingredient = {
id: child.ItemId,
name: child.name,
unit: 1
}
this.allIngredients.push(ingredient);
recipe.ingredients.push(ingredient);
break
case 'recipe':
let subRecipe: Recipe = {
id: child.ItemId,
name: child.name,
ingredients: [],
childRecipes: []
}
await this.recursivelyBuildRecipe(subRecipe)
recipe.childRecipes.push(subRecipe)
break
}
}))
})
// This is returning the same amount of times the recursive function is called, I want it to only return once complete.
var obj = { "recipes": recipe, "ingredients": this.allIngredients }
return await obj;
async recursivelyBuildRecipe(recipe: Recipe) {
const fetch = await this.fetchChildren('http:///recipes/get_children', 'id=' + recipe.id);
const asyncRecipe = await fetch.data.children.reduce(async (accPromise,child) => {
const recipe = await accPromise;
switch(child.type) {
case 'ingredient':
let ingredient: Ingredient = {
id: child.ItemId,
name: child.name,
unit: 1
}
this.allIngredients.push(ingredient);
recipe.ingredients.push(ingredient);
break;
case 'recipe':
let subRecipe: Recipe = {
id: child.ItemId,
name: child.name,
ingredients: [],
childRecipes: []
}
await this.recursivelyBuildRecipe(subRecipe)
recipe.childRecipes.push(subRecipe)
break;
}
return recipe;
},Promise.resolve(recipe));
return { "recipes": asyncRecipe, "ingredients": this.allIngredients }
}
Don't mix Promises and async/await syntax. There's nothing technically incorrect about it, but it's terribly confusing.
You need to iterate over each of the children retrieved and await them. The easiest way to do this, in my opinion, is in a reduce. Although this results in serial retrieval of children - it returns a single object at the end and is easier to reason about. If it's not fast enough, you could do it better with a Promise.all and merge the results yourself.
I'm not sure that the above syntax is 100% correct, but you should be able to get the idea:
I'm not sure I understand specifics here, but it seems what you can do in general is:
Add await for the this.fetchChildren (otherwise it seems like you're getting results because of mutation, not on time).
Add a second boolean parameter to the recursive function (i.e isMainCall), pass it only for the first time (when you start recursion) and add the return in the end into if (isMainCall) return obj

Transform an array of strings to an array of objects with two intermediary $.getJSON calls

Input: an array of username strings
Needed output: an array of Javascript Objects that correspond to each username in the input. The properties for these JS objects is to be built from two API calls for each username (I am using $.getJSON calls. Suggestions welcome).
I have an array of usernames for the Twitch API:
let users = ["OgamingSC2", "storbeck", "comster404"] // actual list is longer
I want to use the Array.prototype.map() higher order function to create an array of objects like
let userObjects = [ {...}, {...}, {...}, ... ]
where each object looks like:
{
username: 'storbeck' // <-- Added by me
stream: null, // <-- Added by first API call
_links: { // <-- Added by first API call
self:'https://api.twitch.tv/kraken/streams/storbeck',
channel:'https://api.twitch.tv/kraken/channels/storbeck'
}
logo: 'http:// ... png' // <-- Added by second API call
}
These are the two API call functions that return the $.getJSON Promises:
let getStreamInfo = (username) => {
return $.getJSON('https://api.twitch.tv/kraken/streams/'+username+'?callback=?')
.then((x) => x) // should I include this then?
}
let getUserInfo = (twitchObject) => {
return $.getJSON('https://api.twitch.tv/kraken/users/'+ twitchObject.user )
}
What I have so far in my code, which isn't resulting in the intended objects is:
let userObjects = users.map((user)=>{
return getStreamInfo(user)
.done((data) => {
let result = {
username: user,
data: data
}
console.log(JSON.stringify(result)) // prints out the intended object so far
return result
})
})
Now when I print out the contents of userObjects, I get:
"{}"
"{}"
"{}"
// ... and so on
Going further, I'd like to chain userObjects and add more to each JS object from whatever I get in the getUserInfo function.
I'd like to go into how this can be done with functional Javascript, but this isn't necessary.
You are on the right way, you need only small edit on your functions.
let getStreamInfo = (username) => {
return $.getJSON('https://api.twitch.tv/kraken/streams/'+username+'?callback=?');
}
let getUserInfo = (user) => {
return $.getJSON('https://api.twitch.tv/kraken/users/'+ user);
}
let userObjects = [];
The core function instead needs Promise synchronization:
users.map((user)=>{
Promise.all(getStreamInfo(user), getUserInfo(user)).then((data)=>{
let obj = {
username: user,
stream: data[0].stream,
_links: data[0]._links,
logo: data[1].logo
}
userObjects.push(obj);
});
});

Categories