Store array from firebase database - javascript

l am trying to build a project using Angular and angularfire. My project is about drawing polygons using leaflet map, then pushing coordinates of a polygon to a database. I have successfully pushed an array to the database, but I have a problem to retrieve coordinates from database.
Database Structure :
{
"Locations" : {
"-M0M9kqEbE0FVMzIZAg0" : {
"text" : [ [ {
"lat" : 35.97800618085566,
"lng" : 42.03369140625001
}, {
"lat" : 33.88865750124075,
"lng" : 41.46240234375001
} ] ]
}
}
}
I am trying to store array above in class ts not in html.
My code :
export class WeatherNowComponent {
itemsRef: AngularFireList<any>;
items: Observable<any[]>;
coords :any
constructor(private db: AngularFireDatabase) {
this.itemsRef = this.db.list('Locations')
// Use snapshotChanges().map() to store the key
this.items = this.itemsRef.snapshotChanges().pipe(
map(changes =>
changes.map(c => ({ key: c.payload.key, ...c.payload.val() }))
)
);
this.db.list('Locations').snapshotChanges().subscribe((markers: any) => {
console.log(markers)
markers.forEach(singlemarker => {
console.log(singlemarker)
// ADD COORDS to MAP POLYGON
var polygon = L.polygon([singlemarker.text.lat,singlemarker.text.lng], {color: 'red'}).addTo(this.map);
});
});
console.log(this.items)
}
}
So I have only key array in console log without rest of array objects.

If you calling a spread operator on purpose because it is an array try assigning it to a property value in the object literal definition.
{ key: c.payload.key, values: ...c.payload.val() }
Edit: Based on your comment I would still say still just assign the array of coordinates (lat/lng property pairs objects) to the values property to iterate over later. I assume the .val() method must return the array of those values. Otherwise please post what .val() returns.
Also, I noticed something else you should check.
The observable is calling the RxJs pipe() method to map but I didn't notice a subscribe() anywhere. While .pipe() lets you map and filter the callback needs a subscribe.
Edit #2: Based on your second comment below. What you are asking for is still unclear to me. So I will give two more possible answers based on the comment: "okay , my question is how i can get array directly ?"
// Possibility #1
// Simplest is to store off the returned data into the coords variable for later processing.
// You can then get the array directly at any later point just by accessing the coords
this.db.list('Locations').snapshotChanges().subscribe((markers: any) => {
coords = markers;
});
// Possibility #2
// Since the data structure you are using works like a dictionary data structure
// Define some structures to store off the data and get at the array data directly later
// Define this somewhere outside your class
interface ICoordinate {
lat: string;
lng: string;
}
// Initialize coordinate dictionary
let coordinates: { [key: string] : ICoordinate[]; } = {};
// Retrieve locations and store off coordinates to get at the array data directly
this.db.list('Locations')
.snapshotChanges()
.subscribe((markers: any) => {
coordinates[markers.key] = ICoordinate[];
markers.forEach(singlemarker => {
coordinates[markers.key].push({ lat: singlemarker.text.lat, lng: singlemarker.text.lng });
});
});
Edit #3: Oh yes, I see. The array needed to be initialized before adding to it.
Updated code. Also, as an additional help to you on future questions it is very helpful if you have a snippet. S.O. question to refer to: I've been told to create a "runnable" example with "Stack Snippets", how do I do that?
Hopefully that helps.
Happy coding!

Related

From single array convert to an array of object with keys coming from a JSON response -JAVASCRIPT-

I am receiving a json response from an API call. I need to store its keys, and create an array of an object. I am intending to this array of an object is created dynamically no matter the keys of the response.
I've already got the keys like this:
const json_getAllKeys = data => {
const keys = data.reduce((keys, obj) => (
keys.concat(Object.keys(obj).filter(key => (
keys.indexOf(key) === -1))
)
), [])
return keys
}
That returned an array (using a sample json):
['name','username', 'email']
But I am trying to use that array to create an array of object that looks like this one
[
{
name: "name",
username: "username",
email: "Email",
}
];
I've been trying mapping the array, but got multiple objects because of the loop, and I need a single one to make it work.
keys.map(i=>({i:i}))
[
{ i: 'id' },
{ i: 'name' },
{ i: 'username' },
{ i: 'email' }
]
Any hint would be useful!
Thanks in advance :D
What you're looking for is Object.fromEntries, which is ECMA2019, I believe, so available in Node >=14 and will be provided as a polyfill if you employ babel.
I can't quite discern what your reduce should produce, but given the sample input, I would write
const input = ['name','username', 'email'];
const result = Object.fromEntries(input.map(name => ([name, name])));
// result == { name: 'name', username: 'username', email: 'email' }
You're definitely on the right track. One thing to remember is the map function will return the SAME number of output as input. So in your example, an array of 3 returns an array of 3 items.
For this reason, map alone is not going to give you what you want. You may be able to map => reduce it. However, here is a way using forEach instead. This isn't a strictly functional programming style solution, but is pretty straight forward and depending on use case, probably good enough.
let keys = ['name','username', 'email'] //you have this array
const obj = {}; // empty object to hold result
keys.forEach(i => {
obj[i] = i; // set the object as you want
})
console.log(obj); // log out the mutated object
// { name: 'name', username: 'username', email: 'email' }

exact array using ES 6 from an array of object

I'm working with Angular 5 http Client to fetch data from an API. This is my subscribe part
vehicles: Vehicle[];
getVehicleList() {
this.vehicleService.getVehicleData()
.subscribe(data => {
this.vehicles = data
console.log(JSON.stringify(data));}
)
}
Vehicle interface
export interface Vehicle {
type: string;
}
I'm getting an JSON look like this
{
"data": [
{
"type": "bus"
},
{
"type": "truck"
},
{
"type": "car"
}
],
"_metadata": null
}
I want to get only array from above using map function. Could someone help me with this?
I'm not sure about what you are asking here, but as Khauri pointed out, you can get the data array by using data.data.
If you want to use map on top of it, it would look like this :
data.data.map(element => console.log(element.type))
This would pritnt
bus
truck
car
[EDIT] If you just want to get the array, you should just use data.data
Assuming you are using typescript, you need to add to your Vehicule interface a data field, which is an array.
in my opinion the solution of the comments before should work.
Please make sure, that you changed your code to the following:
vehicles: Vehicle[];
getVehicleList() {
this.vehicleService.getVehicleData()
.subscribe(data => {
this.vehicles = data.data;
})
}

How to save the objects uid when I push the data in firebase database list, using javascript

I want to save the uid when I push new data in Firebase database. This is possible not for auth users but for data objects.
For example, I want this object schema:
"-Kdsfdsg555555fdsgfsdgfs" : { <------- I want this id
Id : "Kdsfdsg555555fdsgfsdgfs", <--- How to put that inside
name : "A",
time_updated : "6/6/2017"
}
Is any way how to get this id and pushed inside the object?
My code is as follows:
categories: FirebaseListObservable<any[]>;
this.categories = this.db.list('/categories') as FirebaseListObservable<Category[]>;
addCategory(category: any) {
return this.categories.push(category).then( snap => {
this.openSnackBar('New category has been added', 'ok');
}).catch(error => {
this.openSnackBar(error.message, 'ok');
});
}
There are two ways to use Firebase's push() method:
By passing in an argument, it will generate a new location and store the argument there.
By passing in no arguments, it will just generate a new location.
You can use the second way of using push() to just get the new location or its key:
addCategory(category: any) {
var newRef = this.categories.push();
category.Id = newRef.key;
newRef.set(category).then( snap => {
this.openSnackBar('New category has been added', 'ok');
}).catch(error => {
this.openSnackBar(error.message, 'ok');
});
}
But note that it's typically an anti-pattern to store the key of an item inside that item itself too.

ImmutableJs - How to Retrieve Key Based On Position in Map

Im using immutableJs
My state object looks like this:
export const initialToolbarState = Map({
temSelectionCtrl : Map({
temSelect : true,
}),
functionalCtrl : Map({
addEle : true,
grpSelect : true,
drawShape : true
}),
operationalCtrl : Map({
zoomIn : true,
zoomOut : true,
pan : true,
temSide : true
}),
referenceCtrl : Map({
saveCtrl : true
})
});
So there are objects with keys which have boolean values.
I want to map (loop) over these objects & get their keys. The boolean values tell whether to render the key or not. Immutable lets us map over Maps using its custom map function. So, the following works, however not as intended:
// map over the initialToolbarState Map object
let ctrls = initialToolbarState.map(( eachToolbar ) => {
// map over the child Map objects like temSelectionCtrl, functionalCtrl, operationalCtrl etc
return eachToolbar.map(( eachCtrl, i ) => {
// get the key corresponding to 'eachCtrl' value
let propKey = eachToolbar.keyOf( eachCtrl );
// propKey is always the first property (1st prop) of 'eachToolbar'
console.log( propKey );
...
Using immutableJs, is there a way to get the correct key corresponding to the currect 'eachCtrl' value within the loop? Could I make sure of the i to help pointing it towards the correct value for which to match the key?
You can use .map again on your objects. The second argument is the key, with the full argument signature being (mapper (value: V, key: K, iter: this))
So, this snippet:
initialToolbarState.map(( eachToolbar ) => {
eachToolbar.map((value, key) => {
console.log(key, ' ==> ', value);
});
});
Will log:
temSelect ==> true
addEle ==> true
grpSelect ==> true
drawShape ==> true
// etc…
Now just chain your returns to create the data structure that you need or do whatever with your keys.
Also, reconsider if this “Map of Maps” is the best structure for the problems you are solving. Perhaps a “List of Maps” is better if you need to iterate often. You won’t have instant read/update for individual items, but if your list consists of only a couple of items, then the performance will not suffer.

How to update key value in immutable while filtering over List of Maps

I have an immutable List that looks like this:
this.state = {
suggestedUsers: fromJS([
{
user: {
client_user_id: "1234567890",
full_name: "marty mcfly",
image: "imageURL",
role_name: "Associate Graphic Designer",
selected: false
}
},
{
user: {
client_user_id: "0987654321",
full_name: "doc",
image: "imageURL",
role_name: "Software Engineer",
selected: false
}
}
)]
This is used in a div that displays this information in the UI.
When I click on the div, I have a function that is fired that looks like this:
selectUser(clientUserId){
// set assessments variable equal to the current team from the state
let assessments = fromJS(this.state.suggestedUsers)
let selectAssessor
// set a variable called selectedUsers equal to the results of filtering over the current suggestedUsers from the state
let selectedUsers = assessments.filter((obj) => {
// store immutable retrieval of the client user id in a variable called userId
let userId = obj.getIn(["user", "client_user_id"])
// when the user clicks 'Add' user, if the id of the user matches the selected user id
// the user, represented here by obj, is pushed into the selectedUsers array stored in the state.
if(userId === clientUserId){
return obj.setIn(["user", "selected"], true)
}
// If the user id is not equal to the selected user, that team member is kept in the
// current team array represented by the state.
return userId !== clientUserId
})
// update the state with the current representation of the state determined by the user
// selected team members for assessment requests
this.setState({
suggestedUsers: selectedUsers
})
}
The core of my question is this:
I would like to update the value of the 'selected' key in the users object to false, when this function is invoked.
I'm aware that I can't mutate the List I'm filtering over directly, but I've tried may different approaches to getting the selected value updated (i.e. using updateIn, and setIn). I know I need to set the result of calling setIn to a variable, and return that to the List I'm filtering over, but I can't get the value to update in the existing List. Any help is greatly appreciated. Thanks!
I've verified that this works the way it should when I change the value manually. How can I change it with immutable by updating this one List.
=========================================================================
Thank you to the community for your feedback. Filtering, and mapping did turn out to be overkill. Using immutability-helper, I am able to update the selected value of a particular user at the index that is clicked. One caveat that was not mentioned is using merge to bring your updated data into your previous data. After updating with immutability helper, I push the updated value into an array, then make it a List, and merge it into my original data. Code below:
let users = this.state.teamAssessments
let selectedArray = []
users.map((obj, index) => {
let objId = obj.getIn(["user", "client_user_id"])
if(objId === clientUserId){
const selectedUser = update(this.state.teamAssessments.toJS(), {
[index]: {
user : {
selected: {
$set: true
}
}
}
})
selectedArray.push(selectedUser)
}
})
let updatedArray = fromJS(selectedArray).get(0)
let mergedData = users.merge(updatedArray)
this.setState({
teamAssessments: mergedData
})
You need immutability-helper. Basically, instead of cloning the entire object you just modify small pieces of the object and re-set the state after you are finished.
import update from 'immutability-helper';
const newData = update(myData, {
x: {y: {z: {$set: 7}}},
a: {b: {$push: [9]}}
});
this.setState({varName: newData});
In other words, I would ditch the fromJS and the modifying of the array while enumerating it. First, enumerate the array and create your updates. Then, apply the updates separately. Also, to me the "selected" var seems redundant as you know if they are selected because the name of the array after filtration is "selectedUsers."
If I understand your question correctly, here's what I would suggest:
selectUser(clientUserId) {
let suggestedUsers = this.state.suggestedUsers.map(
userBlock =>
userBlock.setIn(
['user', 'selected'],
userBlock.getIn(['user', 'client_user_id']) === clientUserId
)
);
this.setState({
suggestedUsers,
});
}
To confirm -- you are just trying to modify state.suggestedUsers to have selected be true for the selected user, and false for everyone else? Sounds perfect for Immutable's map function (rather than filter, which will just return the elements of the list for which your predicate function returns something truthy).
BTW, you have an error in your object passed into fromJS -- you need an extra }, after the first assessor_assessment block.

Categories

Resources