firebase snapshot.val() returns null - firebase

I'm trying to get user information from Firebase database, but it always returns null.
export const employeesFetch = () => {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/users/${currentUser.uid}/employees`)
.on('value', snapshot => {
console.log("snapshot: ", snapshot.val()) // null
dispatch({ type: EMPLOYEE_FETCH_SUCCESS, payload: snapshot.val() });
});
};
};

If you use numeric IDs for an array of objects, then it will fill in missing items with a null. For example if you don't have an element 0 then your first item will be null.
{
"myList" : [ null, null, {
"myProp" : "thing",
"created" : 1582242432,
}, {
"myProp" : "another",
"created" : 1582242555,
}
}
Why do firebase collections seem to begin with a null row?

According to the documentation, val() returns null when there's no data at the location of the query:
Depending on the data in a DataSnapshot, the val() method may return a scalar type (string, number, or boolean), an array, or an object. It may also return null, indicating that the DataSnapshot is
empty (contains no data).
The internal contents of the DataSnapshot object are not to be used directly. Use the public API instead.

Related

Pass extra arguments to thunk payload in redux toolkit

I'm using the createAsyncThunk method to handle an api request with RTK.
However, I can't get to pass extra arguments to the fulfilled response of the thunk. I can only get the data from the returned promise.
The returned promise has this data:
{ items: [ [Object], [Object] ], metadata: {} }
The action:
export const getGroupsBySchoolId = createAsyncThunk(
'groups/getGroupsBySchoolId',
async (schoolId, _thunkAPI) => {
const { items } = await fetch(someUrl); // simplified fetch request
return { items, schoolId }; // this won't work in the reducer, only if I unwrap() the promise in the component
},
);
in the slice the builder I'm trying to get the schoolId, but I only get the returned promise.
builder.addCase(getGroupsBySchoolId.fulfilled, (state, action) => {
// console.log(action);
const schoolId = action.payload.items.length > 0 ? action.payload.items[0].parentId : null; // i want to avoid this an get it from the payload
state.items[schoolId] = action.payload.items;
state.loading = false;
});
The output from console.loging the action, which is of course, the returned promise and the action type:
{
type: 'groups/getGroupsBySchoolId/fulfilled',
payload: { items: [ [Object], [Object] ], metadata: {} }
}
I could create a regular reducer and dispatch it once the promise has been resolved, but that sounds like an overkill that -I think- shoul be solved in the fulfilled builder callback.
Based on your last comment, I see what you're asking - you want to know how to get access to the thunk argument in the reducer.
In other words, given this:
dispatch(getGroupsBySchoolId(123))
You want to to be able to see the value 123 somewhere in the action when it gets to the reducer.
The good news is this is easy! For createAsyncThunk specifically, the thunk argument will always be available as action.meta.arg. So, this should work:
builder.addCase(getGroupsBySchoolId.fulfilled, (state, action) => {
// console.log(action);
const schoolId = action.meta.arg;
state.items[schoolId] = action.payload.items;
state.loading = false;
});

Query array of object in firestore

i have a collection that is called employees, which includes documents and each document contains some data, and an array of objects that is called orgsanizations, for instance:
orgsanizations: [
{
orgId: 'org1',
registrationDate: '08/05/2021',
status: 'pending'
},
{
orgId: 'org2,
registrationDate: '12/01/2021',
status: 'approved'
}
];
I am trying to retrieve all the documents in employees that contains orgId === org1 in the orgsanizations, here is what i tried to do but keeps returning empty array.
const allEmployees = async () => {
const employeesList = db.collection('employees');
const snapshot = await employeesList
.where('orgsanizations', 'array-contains', { orgId: 'org1' })
.get();
if (snapshot.empty) {
console.log(snapshot.empty);
} else {
snapshot.forEach((doc) => {
console.log(doc.data());
});
}
};
};
Is there a solution for this or should start considering changing the structure to something else?
Thanks in advance
You can't check for the contents of a map, using array-contains. There are a couple of solutions for this...
Create a second array called orgIds, which contains only the orgId strings. You can then find any documents which contain these orgIds. To achieve this, you will need to write the orgId into the map AND the orgIds array.
Create an organizations sub-collection of your employee document and use a collectionGroup query.
{
organizations: [
{orgId: 'org1', registrationDate: '08/05/2021', status: 'pending'},
{orgId: 'org2', registrationDate: '12/01/2021', status: 'approved'}
],
orgIds: ['org1', 'org2']
}
const employeesList = db.collection('employees');
const snapshot = await employeesList
.where('orgIds', 'array-contains', 'org1')
.get();
You may also want to change your registrationDate to either a Timestamp or an ISO8601 string, so that you can sort them (if needed).

How to execute buisness logic in NgRx reducers

Hi am using NgRx store for state management in my angular project.
My goal is to clear few state properties on action dispatch. The array of property names are passed to the action.
// Action
export const clearFields = createAction(
'[SC Base Data] Clear Fields',
props<{ fields: string[] }>()
);
// Reducers
on(SCActions.clearFields, (state: SCState,fields: string[]) => ({
...state,
SCData: {
...state.SCData
}
})),
/
How can iterate over fields array and set the state properties value as blank
If by "blank" you mean null, I believe what you're looking for is something along these lines:
on(SCActions.clearFields, (state: SCState, fields: string[]) => ({
// create an Object whose keys are all elements of fields and every value is null
const clearedState = {};
fields.forEach(field => {
clearedState[field] = null;
});
// return new copy of state nulling all fields from fields array
return {
...state,
...clearedState
};
}))

Firebase Firestore returns a promise in Vue

I'm trying to use some data from from Firestore. before it used to work, now in Vuetify I keep getting 'PENDING' if I try to access the $data.users
export default {
data() {
return {
users: [],
};
},
created() {
db.collection('users').get().then((snapshot) => {
snapshot.forEach((doc) => {
const user = doc.data();
user.id = doc.id;
this.users = user;
console.log(user.documents.selfie.url); // Here the log return the value correctly
});
});
},
methods: {
imageUrl(user) {
console.log(user.documents.selfie.url); // Here the log return "Pending";
},
Inside the template I run a v-for (user, index) in users :key='index'
ERROR:
Uncaught (in promise) TypeError: Cannot read property 'selfie' of undefined
It's difficult to be 100% sure without reproducing your problem, but I think the problem comes from the fact that the Promise returned by the asynchronous get() method is not yet fulfilled when you call the imageUrl() method. This is why you get the pending value.
One possibility to solve that is to check as follows:
methods: {
imageUrl(user) {
if (user) {
console.log(user.documents.selfie.url);
} else {
//...
}
},
Also, is seems you want to populate the users Array with the docs from the users collection. You should do as follows:
created() {
db.collection('users').get().then((snapshot) => {
let usersArray = [];
snapshot.forEach((doc) => {
const user = doc.data();
user.id = doc.id;
usersArray.push(user);
console.log(user.documents.selfie.url); // Here the log return the value correctly
});
this.users = usersArray;
});
},
With your current code you assign the last user in the loop, not the list of users.

flutter firestore, add new object in array

I have array of objects, I want to add new object when user enter new data in the array?
Firestore.instance.collection(city).document('Attractions').updateData(
"data", FieldValue.arrayUnion(obj)
);
This shows error, How can I achieve this with flutter?
Right Format is :
Firestore.instance.collection(city).document('Attractions').updateData({"data": FieldValue.arrayUnion(obj)});
updateData Take Map<String,dynamic> as data.
In your Code you are having , as separator between key - value instead it should be :
#anmol.majhail 's is right, but to solve #Sami Ullah's problem, you must first make a list and add the object into the list like this:
var list = [objectBeingAdded];
Firestore.instance.collection('city').document('Attractions').updateData({"data": FieldValue.arrayUnion(list)});
Null safe code:
Say this is the data you want to add
Map<String, dynamic> someData = {
'foo': 1,
'bar': true,
};
Add the data with unique auto-generated ID:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.add(someData)
.then((_) => print('Added'))
.catchError((error) => print('Add failed: $error'));
Add the data with your own ID:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('document_id') // <-- Document ID
.set(someData)
.then((_) => print('Added'))
.catchError((error) => print('Add failed: $error'));
Add the object to an array:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('document_id') // <-- Document ID
.set({'data': FieldValue.arrayUnion(list)}) // <-- Add data
.then((_) => print('Added'))
.catchError((error) => print('Add failed: $error'));
This is a working function I built that adds new Maps to an array in my Firestore Services class. I'm using Json Serializable to annotate all my model classes. userTemplateSections is a data field in my userTemplate firestore documents. I take userTemplate as a constructor of the 'addUserTemplateSection' function to make sure I'm editing the correct document.
I also added the function I made to delete Maps from a firestore document array.
'''
Future<void> addUserTemplateSection(
{UserTemplate userTemplate, String title, String summary}) async {
try {
final UserTemplateSection userTemplateSection =
UserTemplateSection(title: title, summary: summary);
await _firestore
.document(FirestorePath.userTemplate(uid, userTemplate.id))
.updateData(
{
'userTemplateSections':
FieldValue.arrayUnion([userTemplateSection.toJson()])
},
);
} catch (e) {
print(e);
}
}
'''
'''
Future<void> deleteUserTemplateSection({
UserTemplate userTemplate,
UserTemplateSection userTemplateSection,
}) async {
try {
await _firestore
.document(FirestorePath.userTemplate(uid, userTemplate.id))
.updateData(
{
'userTemplateSections':
FieldValue.arrayRemove([userTemplateSection.toJson()])
},
);
} catch (e) {
print(e);
}
}
'''

Resources