Flutter Firestore Can I create collections using a Map - firebase

my question is, can I create 1 document in multiple collections using a single:
firestore
.collection('map')
.doc('documentvariable')
.set(data());
Where instead "map" would be an actual Map with list of String names for collections into which I would like to add the document.
Reason why I chose a Map is because I need to be able to add more and more collections to it using UI.
Is it possible and if so is there a better solution for this?

That's not possible as .collection only accept a String. As others mentioned in the comments you can simply iterate through the list of collection names you want to add the document to. Something like this.
List<String> allCollectionNamesYouWant = ['collection1', 'collection2'];
for(String collectionName in allCollectionNamesYouWant){
FirebaseFirestore.instance
.collection(collectionName)
.doc('documentvariable')
.set(data());
}

Related

How to create one stream listening to multiple Firestore documents created from list of documents references in Flutter

Im trying to create one stream, that is using multiple documents references that are stored and fetched from Firebase Firestore.
Lets say I have two collection named users and documents. When user is created he gets document with his id in users collection with field named documentsHasAccessTo that is list of references to documents inside documents collection. It is important, that these documents can be located in different sub collections inside documents collection so I dont want to query whole documents and filter it, in order to save Firestore transfer and make it faster I already know paths to documents stored in documentsHasAccessTo field.
So for example, I can have user with data inside users/<user uid> document with documentsHasAccessTo field that stores 3 different document references.
I would like to achieve something like this (untested):
final userId = 'blablakfn1n21n4109';
final usersDocumentRef = FirebaseFirestore.instance.doc('users/$userId');
usersDocumentRef.snapshots().listen((snapshot) {
final references = snapshot.data()['documentsHasAccessTo'] as List<DocumentReference>;
final documentsStream = // create single query stream using all references from list
});
Keep in mind, that it would also be great, if this stream would update query if documentsHasAccessTo changes like in the example above, hence I used snapshots() on usersDocumentReferences rather than single get() fetch.
The more I think about this Im starting to believe this is simple impossible or theres a more simple and clean solution. Im open to anything.
You could use rxdart's switchMap and MergeStream:
usersDocumentRef.snapshots().switchMap((snapshot) {
final references = snapshot.data()['documentsHasAccessTo'] as List<DocumentReference>;
return MergeStream(references.map(ref) => /* do something that creates a stream */));
});

editing document and field in firebase

im working on firebase and im trying to update the document name and its field name together like shown in the image. i want them to be updated together.
i used this code
EditCourse(String cName, String newName) async {
var collection = FirebaseFirestore.instance.collection("Courses")
..where("Course name", isEqualTo: cName);
collection.doc(cName).update({'Course name': newName});
}
Answer:
As of Now Firebase not allows to update documents ids)
Suggestion:
You should use relational ids or random ids
(relational ids means suppose you have seller favorite collection you can give documents ids to movie/food ids)
There is no way to update the document ID of an existing document. If changing course names is a use-case you need to support, consider using Firestore's built-in ID generation when adding your documents (so add documents using the add() method).
If you stick to your current model, you'll have to:
Read the existing document.
Write the date under the new ID.
Delete the original document.
Given the type of operation, you'll probably want to use a transaction for that.

Flutter Firebase: Retrieve a list of documents, limited to IDs in an array?

I'm working on a Flutter app where each user can create projects, and share projects with other users. I've created a 'shares' collection, where each user's ID is a document, and within that document, all project IDs that have been shared with that user are collected like so, with a boolean that represents whether or not the share has been accepted yet:
Next, I created a collection of the projects themselves, like so:
Now, I'd like to query the 'projects' collection and return only the projects that are in a given user's 'shares' list. First off, how can I get each document in the share list's ID? And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
I've been trying something like this, but to no avail:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: ref.id)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
I also tried this:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: FieldPath.documentId)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
Is what I'm trying to do even possible? I've been messing with this for two days and my head's exploding. Any help would be greatly appreciated. Thanks in advance.
You'll need two operations.
Read the document for the user, to determine the list of project IDs.
Perform a in query for the project documents matching those IDs. The in operator accepts up to 10 IDs, so if you have more than 10 projects you'll need multiple queries and merge the results in your application code.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, arrayContains: ['project1id', 'project2id']);
Also see:
The FlutterFire documentation for the where(field, whereIn:) operation
The FlutterFire documentation for the FieldPath.documentId field
First off, how can I get each document in the share list's ID?
For this, you're required to actually query the entire collection. You can iterate the results to collect the IDs of each document. There is no easy way to just get a list of IDs directly from web and mobile client code. See: How to get a list of document IDs in a collection Cloud Firestore?
And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
If you have a list of document ID strings in memory that could be any length, you will need to perform a query filtering projects for "projOwner" for each individual ID. There are no SQL-like joins in Firestore, so you can't simply join the two collections together with a single query.
Here's how you do a single one - you have to call out the name of the field to filter on:
firestore
.collection("projects")
.where("projOwner", isEqualTo: id)
If you have 10 or less share IDs in the list, you can use an "in" query to find matches from projects, and it will not work with any more.
firestore
.collection("projects")
.where("projOwner", whereIn: listOfIds)
So, if you think the list could ever be larger than 10, you should just start by performing individual queries for each share ID.
if 'arrayContains' is not working try 'whereIn'.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, whereIn: ['project1id',
'project2id']);

How do I get list of the document ID's inside a collection without getting the content of the documents in Firestore?

I want to do something like:
final collectionReference = Firestore.instance.collection('myCollection');
final List<String> documentList = collectionReference.getDocList();
OR
final query = collectionReference.orderBy('lastUpdated', descending: true).limit(100);
final List<String> documentList = query.getDocList();
Currently when we use get() or query.getDocuments() it will return the whole Document list and all contents along with it. But you know that we wanna optimize reads thus we make use of the 1MiB limit of each Documents. Thus we don't wanna download the whole document's contents. Rather we just need the IDs for other usage. Is there a way to do this ?
Thanks
There no way to do this with the Flutter APIs (or any of the web or mobile clients).
The only way is with backend code, where you have a method like select() (link to the nodejs API) on Query that lets you select which document fields to return. So, you could have your app call a backend to return the document IDs, but not directly in the app.
If you must query from the client, consider moving fields unnecessary for queries to documents in anther collection with the same IDs, and request them only when needed.

Firestore: How to query data from a map of an array

Here is the schema for test db:
I want to write a query that can get all the documents where contacts have id=1 in any of the array index.
I have checked array_contains operator for firestore but the thing is my array have map which then have field id.
Thanks
You currently can't build a query that looks for an object field within an array. The only things you can find in an array are the entire contents of an array element, not a part of an element.
With NoSQL type databases, the usual practice is to structure you data in a way that suits your queries. So, in your case, you're going to have to structure your data to let you find documents where an array item contains a certain string. So, you could create another array that contains just the strings you want to query for. You will have make sure to keep these arrays up to date.
You could also reconsider the use of an array here. Arrays are good for positional data, but unless these contacts need to be stored in a certain order, you might want to instead store an object whose keys are the id, and whose field data also contains the id and name.
As Doug said, you can't query it,
but, if you could structure your data to something that looks like this
Store your data as a map
Use id as key and name as value
Now you can write a query that can get all the documents where contacts have id=1
db.collection("test").where("contacts.1", ">=", "").get()
If you have an array of maps or objects and want to get the docoments that contains this specific map/object like this ?
array_of_maps.png
you can use
queryForCategory(categName: string, categAlias: string): Observable[] {
firestore.collection('<Collection name>', ref =>
ref.where('categories',
"array-contains", {
"alias": categAlias,
"title": categName
}
One soulions is as #Doug said, to add array with the data you need to query, and keep it uptodate.
Another solution is to make contacts as sub collection of the document, an then you could make queries of the contacts and get its parrent.
final Query contacts = db.collectionGroup("contacts").whereEqualTo("id", 1);
for (DocumentSnapshot document : querySnapshot.get().getDocuments()) {
System.out.println(document.getId());
System.out.println(document.getString("parent_id"));
}
If you don't want to add parent as another field, you can get it from parent reference, check this answer https://stackoverflow.com/a/56223319/1278463
snapshot.getRef().getParent().getParent().collection("people")
https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query

Resources