Object Mapping in Flutter to Realtime DB Firebase - firebase

I want to save my List with Objects in Firebase Realtime DB. The Problem is, that when I save my objects there, they dont have an auto generated key, their key is 0, 1, 2,... :
I am mapping my Poll object this way:
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'allowBarChart': allowBarChart,
'allowPieChart': allowPieChart,
'description': description,
'custom-questions': customQuestions != null
? List<dynamic>.from(customQuestions.map((x) => x.toJson()))
: [],
'choice-questions': choiceQuestions != null
? List<dynamic>.from(choiceQuestions.map((x) => x.toJson()))
: [],
};
My Question is: how to do it, so the key of each value is not 0,1,2,3,... It should be auto generated from firebase, for example: 1fdDfasLPO3g. I hope you know what I mean.
Thanks in advance!

When the Firebase SDK encounters a List it is mapped to a JSON array, which is stored with sequential numeric indices, as seen in the screenshot you shared. There is no way to change this mapping.
If you want to store items with Firebase's push keys (which start with -M at the moment), you should generate those in your application code (by calling push()), and store the questions in a Map<string, dynamic>.

Related

Querying FireBase FireStore Document in Flutter

I wants to achieve one query which i'm trying for few hours in FireStore Database, Please check the below image,
The Query I want to do is, In the document which I marked, will have a list of group id (combination of 2 userIds in each , userId1-userId2), I want to query this document by having one userId that contains in the group id (before or after hyphen) and returns a list of snapshots , which should be used for StreamBuilder in a list widget.
For Example:
I may have 'abcdefghijkl' userId, I want to check each document ID that contains this userId, and returns a list of snapshots which matches.
Thanks in Advance!
I don't think the query you want is possible, since there is no operation to check if a document id contains something. I would recommend adding a participants array to the document and than use an array-contains query, see also here.
There are several ways to achieve what you're after - a list of users relating to a given document - but I think you should rethink your data structure first. Each message document should have a users field that is an array of Firestore document IDs which would contain 1 or more document IDs of the users that this message relates to.
With that, you can easily query the database for all messages where a given user is referenced:
final messages = db
.collection('messages')
.where('users', arrayContains: userId)
.get();
BTW, to take things a step further, I would structure my data like this:
user {
displayName: '',
email: '',
messages: [
{
authorId: userId,
content: '',
users: [userId, ...],
sentOn: '',
},
...
]
}
With this you can do two things:
Fetch all messages created by the user:
final userMessages = db.doc(userId).collection('messages').get();
Fetch all messages where user participated:
final allUserMessages = db
.collectionGroup('messages')
.where('users', arrayContains: userId)
.get();
Check out the Firestore docs, as they have plenty of examples there.

How to use FieldPath.of() in Firebase Firestore with Flutter

I'm trying to update a nested document field in Firebase Firestore, but when I use the FieldPath instance, It raises a compiler exception
Map _map = {
'name': 'vin',
'quantity': 2,
'costPrice': 12000,
};
var fieldPath = new FieldPath(['categories', 'branch']);
final CollectionReference _storeRef =
FirebaseFirestore.instance.collection('stores');
_storeRef.doc('6').update({fieldPath: _map});
How do I update a nested document Field using the Firebase FieldPath instance
The DocumentReference.update method requires a Map<String, dynamic> as it's first parameter and the reason for the compiler error is because you're trying to pass a FieldPath object instead of a String.
You can reduce the values of the FieldPath into a String and use that as the path for the update method.
Update this:
_storeRef.doc('6').update({fieldPath: _map});
to this:
_storeRef
.doc('6')
.update({'${fieldPath.components.reduce((a, b) => '$a.$b')}': _map});
This basically means the same as:
_storeRef
.doc('6')
.update({'categories.branch': _map});

How do i find value from the collection value of the array by comparing ID in firebase on snapshot in React-native?

I have a collection called doctors. I need to find only that data from collection which has current user inside the allParticipants
ex:
doctors.allParticipants.userID == userID
As you can see in the allParticipants has array of data
is there any way to find this data using where condition or any else please help me to figure out this
You can use array-contains operator however you need to know the complete user object for that as it's an array of object and not strings. For example,
const userObj = {
channel: "/channels/channelId",
user: "/users/userId",
userID: "userId"
}
const colRef = firebase.firestore().collection("channels")
colRef.where("allParticipants", "array-contains", userObj).get().then(snap => {
console.log(`${snap.size} documents found`)
})
If you could store an array of userID (string) only, then the query would be as easy as:
const {uid} = firebase.auth().currentUsers.uid
const query = colRef.where("participantUIDs", "array-contains", uid)
But if you need to keep that array of objects, then you'll first need to fetch that user's channel ID and follow method 1.

FIrebase setData kef-value sequence not preserved

I am trying to add data in firebase as the key-value sequence I have provided in setData.
create({Function onAdded, Function onDuplicate}) async {
bool temp = await lrCheck();
if (temp) {
await fireStore.collection("Admin").document(TextFieldData.lrNO).setData(
{
"lrNO": TextFieldData.lrNO,
"departureDate": TextFieldData.departureDate,
"partyName": TextFieldData.partyName,
"vehicleNo": TextFieldData.vehicleNo,
"origin": TextFieldData.origin,
"destination": TextFieldData.destination,
"quantity": TextFieldData.quantity,
"invoiceNo": TextFieldData.invoiceValue,
"invoiceValue": TextFieldData.invoiceValue,
"arrivalDate": TextFieldData.arrivalDate,
"materialType": TextFieldData.materialType,
"phoneNo": TextFieldData.phoneNo,
},
).whenComplete(onAdded());
But the data stored in firebase is in alphabatical orer of keys plzz help.
ex:
arrivalDate: value
destination: value
and so on ....
Fierstore does not set an order for the fields in a document. If you need an order, you will have to apply that in your app code. If you have an array of ordered data to store, consider putting that data in a single list type field instead.
The data in the firebase document are stored in key-value pairs so, There should be no problem even if the data is received in unordered fashion as long as you are mapping the data correctly in your model.

Determine RTDB url in a trigger function

i m bulding a scalable chat app with RTDB and firestore
here is my raw structure of shards
SHARD1
Chats {
chat01: {
Info: {
// some info about this chatroom
},
Messages ...
}, ....
}
SHARD2...
now i have write triggers on all the info nodes of all the shards.
i want get the ID of the shard
How do i know what shard it actually ran on ?
[EDIT]
console.log(admin.app().name); // it prints "[DEFAULT]" in console
Puf and team please help
When a Realtime Database trigger is invoked, the second argument is an EventContext object that contains information about the database and node that was updated. That object contains a resource string, which has what you're looking for. According to the documentation for that string, it's name property will be formatted as:
projects/_/instances/<databaseInstance>/refs/<databasePath>
The databaseInstance string is what you're looking for. So, you can just split the string on "/" and take the 4th element of that array:
export const yourFunction = functions.database
.instance('yourShard')
.ref('yourNode')
.onCreate((snap, context) => {
const parts = context.resource.name.split('/')
const shard = parts[3]
console.log(shard)
})
If all you need is a reference to the location of the change, in order to perform some changes there, you can just use the ref property on the DataSnapshot that was delivered in the first argument, and build a path relative to there.

Resources