How will i be able to retrieve the field and field values from firebase?
i want to retrieve "total payment" and its value and store it in array. Below is my code for getting the field values but not the field names.
Future _getDataFromDatabase() async {
await FirebaseFirestore.instance.collection("payments").doc(FirebaseAuth.instance.currentUser!.uid).get().then((snapshot)async{
if(snapshot.exists){
setState((){
totalPayments = snapshot.data()!["total payment"].toString();
balance = snapshot.data()!["remaining balance"].toString();
print(totalPayments);
});
}
});
}
snapshot is of type Map<String, dynamic> so if I understand your question correctly you are asking how to cast a map into a list with its keys preserved as string values.
you can get a list of a key-value pairs using something like
IterableZip([snapshot.keys, snapshot.values])
and then you can flatten it into a list using any approach but the shortest would be using expand
so the final code would be:
import 'package:collection/collection.dart';
//... after that you can use
IterableZip([snapshot.keys, snapshot.values]).expand((i) => i).toList()
Related
I am trying to get all documents where the length of the "users" array is less than 2 and where the userId is not present already. I am doing the following query, but it is not executing correctly. What is the problem and how can I fix it? I just want all documents where there is only one entry in the array "users" and where the array does NOT contain the current userId.
await FirebaseFirestore.instance
.collection('rooms')
.where("users"[0], isNotEqualTo: userId)
.where('users'[1], isEqualTo: null)
.get()
.then((snapshot) async {
// If no empty room is found, create room
if (snapshot.docs.isEmpty) {
print("No empty room found, creating new room");
roomId = await createRoom(userId);
return roomId;
}
You can't query individual array elements in Firestore. You can only check whether an array contains a specific item.
It sounds like your array items have a specific meaning, in which case you should create (nested) fields that indicate/name the roles. For example:
participants: {
creator: "uid1",
receiver: "uid2"
}
With that you can then query the nested fields with dot notation:
.where("participants.creator", "!=", "uid1")
.where("participants.receiver", "==", null)
Keep in mind there that the participants.receiver field still has to exist in the latter case and have a value of null. Firestore can't filter in fields that don't exist.
I wanted to add a string values to a realtime firebase database with the firebase UID being the name and the string being the value. When I use the below code it makes the UID a parent node and set the value to a child node.
ReferralCode referralCode = new ReferralCode(refCode); databaseReference.child("referralCodes").child(userId).setValue(referralCode);
I wanted the values to be populated as the second one. But with the above code,i get the first result. I'm going to search for the referral codes afterwards,so i think it would be faster if the values are populated as the second one to avoid accessing a child node which will be time consuming for large database entities.
When you are using a Model like you created ReferralCode and using it to with .setValue(referralCode) then Firebase will automatically create it as the child with attributes your ReferralCode.java has. Example below:
public class Restaurant {
private int code;
private int type;
private String name;
}
So if I create a variable Restaurant tempRest = new Restaurant(111, "Restoran DM", 0) and use it like this:
database.child("restaurants").child("1st restaurant").setValue(tempRest);
Firebase will create something like this:
restaurants
1st restaurant:
code: 111
name: "Restoran DM"
type: 0
But if you use String in setValue() like this:
String someValue = "some value";
database.child("restaurants").child("awpjawpdaw").setValue(someValue);
it will give you what you want. Example, I used this:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
String refCode = "1231231";
database.child("restaurants").child("wadawdapwodawp").setValue(refCode);
and here is what happened in database:
Hi I am pretty new to Firebase real time database and this is my first project. Sorry if this is a stupid question.
I am saving my data as follows.
firebase database structure:
Now I want to retrieve all parent chat ids on which the student is participating, using the student_id variable.
I tried as per this SO question and this structure database and retrieve data documentation, but its not retrieving values. Anybody have an idea?
I would suggest saving the chatroom IDs your students are in in a separate location. For example:
Path:
“/users/$uid/chatrooms”
Data:
{
0: 350,
1: 423
}
Thus you could retrieve the chat room ids first before getting the chatroom data.
import { initializeApp } from “firebase”;
import { getDatabase, get, set, ref } from “firebase/database”;
const userChatroomIdsRef = ref(db, ‘/users/${uid}/chatrooms‘);
get(userChatroomIdsRef).then(result => {
const chatroomIds = result.val();
if (!(chatroomIds && chatroomIds instanceof Array)) return; // firebase will return null if its an empty array.
const getChatroomInfoPromises = chatroomIds.map(id => get(ref(db, ‘/chat/${id}/${uid}’)).then(result => result.val());
Promise.all(getChatroomInfoPromises).then(chatroomInfoArray => { YOUR LOGIC HERE });
});
Removing/adding students from/to chatrooms would now be simple as you could just change the array of chatroomIds.
const userChatroomIdsRef = ref(db, ‘/users/${uid}/chatrooms‘);
get(userChatroomIdsRef).then(result => {
const oldIds = result.val();
const newChatroomIds = oldIds.filter(id => id !== ID TO DELETE);
return set(userChatroomIdsRef, newChatroomIds)
});
This is of course assuming that you know the uid of your student_id. If you do not know what uid each student_id has, you must must store a reference. I would suggest saving all student info in the “/users/$uid/” directory. Here you could save the studentId so you can programmatically use it.
In all other firebase logic I would try to use the native firebase uid for querying. This will make your life easier.
It’s always good the keep information organized on the database so your logic is simple.
Please check my code for syntax errors; I wrote this on an iPhone.
I want to add a field of type array inside a collection.
if the field doesn't exist create it. if it exists overwrite it with the new array value.
the field should be called macAddress and it's of type array of String
I have tried the following:
val macInput = setting_mac_text.text.toString()
val macArray = macInput.split(",")
val macList = Arrays.asList(macArray)
val data =
hashMapOf(Pair(FirebaseConstants.USER_MAC_ADDRESS, macArray))
//save it in firebase
db.collection(FirebaseConstants.ORGANIZATION)
.document(orgID + ".${FirebaseConstants.USER_MAC_ADDRESS}")
.set(FieldValue.arrayUnion(macList))
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d(TAG, "successfully inserted")
} else {
Log.d(TAG, " failed ${task.exception}")
}
}
also tried to insert the list itself and hash map like this
val data = hashMapOf(Pair(FirebaseConstants.USER_MAC_ADDRESS, macArray))
db.collection(FirebaseConstants.ORGANIZATION)
.document(orgID)
.set(data))
but it keeps giving me java.lang.IllegalArgumentException: Invalid data. Nested arrays are not supported
what am I doing wrong here?
You're doing three things wrong here:
FieldValue.arrayUnion() is only meant to be used as the value of a field to add elements to that field. The way you are using it now in the first sample, it's being taken as the entire contents of the document.
set() with one parameter is only intended to create or overwrite an entire document. It can't be used to update an existing document. You would have to pass in SetOptions to tell it to merge if you want an update. Or, you would simply use update() to modify an existing document.
Your code that deals with macArray and macList isn't working the way you expect. You are creating a list with one element, which is itself an array. The error message is telling you that you can't have nested arrays like this.
I suggest taking a step back and simplifying your code, removing all the moving parts that don't have to do with Firestore. Just hard code values in your Firestore update until the update works the way you want, then add in the code that works with actual values. Get one simple thing to work, then add to it. If you get an error, you will know that the code you just added was incorrect.
To overwrite an array, you would simply call the set method and have the merge option set to true:
try {
const query = await DatabaseService.queryBuilder({
collection: CollectionName,
});
return await query
.doc(insuranceId)
.set(
{ DOCUMENT_PROPERTY_HERE: ARRAY_HERE },
{ merge: true }
);
} catch (exception) {
return Promise.reject(exception);
}
I want to return a list of members via a StreamController.
batches collection contains batch details and ids of members assigned to the batch.
So, in-order to get the list of members in a batch, have to loop through batch collection and get the ids of members, then match with members collection and return the matching member data as stream.
final CollectionReference _batchCollectionReference =
Firestore.instance.collection('batches');
final CollectionReference _membersCollectionReference =
Firestore.instance.collection('members');
final StreamController<List<Member>> _membersController =
StreamController<List<Member>>.broadcast();
Stream getMembers(String batchId) { //passing a batch id
_batchCollectionReference
.document(batchId)
.snapshots()
.map((batchSnapshot) => Batch.fromData( //return as Batch type
data: batchSnapshot.data, batchId: batchSnapshot.documentID))
.listen((snapshot) {
List<String> members = snapshot.members; //list of members
members.forEach((member) {
var data = _membersCollectionReference
.document(member)
.snapshots()
.map((memberData) => Member.fromData(data: memberData.data)); //return as Member type
_membersController.add(data);
});
});
return _membersController.stream;
}
}
The problem is I couldn't able to push the member data to the StreamContoller.
It says,
The argument type 'Stream<Member>' can't be assigned to the parameter type 'List<Member>'
The stream should contains instance of members; Ex: [[instance of 'Member'], [instance of 'Member'], [instance of 'Member']]
If I got the data like this way, it would be easy to loop and do the other stuff.
I couldn't able fix this issue. Any help would be appreciated.
Firstable when you need to add a list to the stream so convert your map data to a list, just adding toList() at the end of you map as follows:
members.forEach((member) {
var data = _membersCollectionReference
.document(member)
.snapshots()
.map((memberData) => Member.fromData(data: memberData.data)).toList();
And to push the data in the Stream, you need to use sink.add() this can be an example of a function to push data into the stream and the other one to get the values:
final StreamController<List<Member>> _membersController = StreamController<List<Member>>.broadcast();
/// Inputs
Function(List<Member>) get changeMembers => _membersController.sink.add;
/// Getters
String get members => _membersController.value;
In your case you can do it directly in this way:
_membersController.sink.add(data);
Hope it helps, for more info please check this video or the documentation about streams in dart.