I'm creating a simple job board site.
You have a JobSeeker, a JobListing and a JobApplication
Both the JobSeeker and the JobListing should have a collection of JobApplications.
When a JobSeeker applies for a job, I want to create a JobApplication document, and add it to both the JobSeeker's collection, and the JobListing's collection.
But that should be a reference to a single document. (ie. if you update it in one place, it should update in the other).
How do I achieve this?
I see according to this answer:
Cloud Firestore multiples document with the same reference
I can add a Reference as a datatype in Firestore - but I'm not exactly sure which method to use to add it.
ie. the collection.add method accepts DocumentData, but I can't see how to set that as a reference?
Can you tell me what syntax to use to:
Create the JobApplication document
Add the document reference to a collection.
Retrieve the document reference from either collection.
Here's the way I ended up solving this:
To set the data:
const docData = {
listingId: "someExistingId",
jobSeekerId: "anotherExistingId",
otherData: "whatever other data goes here",
}
const docRef = await db.collection("job-application-collection")
.add(docData);
await db.collection(`job-seeker-collection/${docData.jobSeekerId}/applications`)
.add({ref:docRef});
await db.collection(`job-listing-collection/${docData.listingId}/applications`)
.add({ref:docRef});
That as, what we do is we create one 'real' document, that goes into the job-application-collection and in the JobSeeker and JobListing collections we add a 'pointer document' that just contains a single field ref, containing the document reference.
To retrieve it (in this example, retrieve all of the applications for a given JobSeeker):
const jobSeekerId = "someJobSeekerId";
const colRef = await db.collection(`job-seeker-collection/$jobSeekerId}/applications`);
const colSnapshot = await colRef.get();
/**
* The docs on the collection are actually just documents containing a reference to the actual JobApplication document.
*/
const docsProms = colSnapshot.docs.map((async (colDocData) => {
const snapshot = await colDocData.data().ref.get();
return {
...snapshot.data(),
id: snapshot.id,
}
}));
const data = await Promise.all(docsProms);
return data;
Pretty straight forward, we get the collection on the JobSeeker document, and then on each of those documents, there is a ref field, which we can use the .get() method to return a document snapshot.
Related
I have a collection in firebase called "community" and "users". All user records have a field "joinedCommunity" (a list of all joined communities).
I'm trying to figure a code that when a community is deleted, all user records are updated to only remove the community reference from "joinedCommunity" field list.
building this in flutterflow using custom action
onTap on a button in UI, the code is included as one of the actions before community document is deleted.
Future userRecordUpdate(DocumentReference community) async {
final instance = FirebaseFirestore.instance;
final batch = instance.batch();
var collection = instance.collection('users');
batch.update(collection, {
"joinedCommunity": FieldValue.arrayRemove([community])
});
await batch.commit();
}
You're using a CollectionReference, when what you want is a DocumentReference. As per the documentation, WriteBatch.update only works on a DocumentReference.
I have a few suggestions:
Try updating the field without using a WriteBatch. Use a for loop and a regular DocumentReference.update() call.
Then, update your code to use a WriteBatch to update the field. Also, keep in mind a batch is limited to 500 operations.
Finally, consider the security implications of allowing a client to be able to update any User document. You should probably update your security rules so that a user document can only be modified by that user. This code is probably something that should run in a Firebase Cloud Function that gets triggered whenever a community document is deleted.
the following code worked -
Future userRecordUpdate(DocumentReference community) async {
final instance = FirebaseFirestore.instance;
final batch = instance.batch();
var collection = instance.collection('users');
var snapshots =
await collection.where("joinedCommunity", arrayContains:
community).get();
for (var doc in snapshots.docs) {
batch.update(doc.reference, {
"joinedCommunity": FieldValue.arrayRemove([community])
});
}
await batch.commit();
}
I can't seem to figure out how to get a List after querying a specific Firestore collection.
I want the function to:
Query the 'chat' collection on the field 'users'.
Retrieve only the document (should be only one but could be an error and there's more than one) where users, which is a LIST of Document Reference, matches two specific references: chatUserRef and authUserRef
The function should return a list of the Document References referring to this chat collection
This is what I am trying:
import 'package:cloud_firestore/cloud_firestore.dart';
Future<List<ChatsRecord>> getChatDoc(
DocumentReference chatUserRef,
DocumentReference authUserRef,
) async {
// Add your function code here!
final firestore =
FirebaseFirestore.instance; // Get a reference to the Firestore database
final collectionRef =
firestore.collection('chats'); // Get a reference to the collection
final filteredDocuments = collectionRef.where('users', isEqualTo: [
authUserRef,
chatUserRef
]); // Use the `where` method to filter the list of documents
final queryDocuments = await filteredDocuments
.get(); // You can then use the get method on this Query object to retrieve the list of documents AS a Snapshot Document (this is NOT a list of the Documents themselves).
List<ChatsRecord> listChatDocs = [];
// Cast the Snapshot Documents to a map
// Extract the Document Reference ID
// cast the query document to a map for e
// (should I forEach?)
List<ChatsRecord> listChatDocs = queryDocuments.docs.map((e) {
return FirebaseFirestore.instance.doc('chats/$e.id');
}).toList();
return listChatDocs;
}
Try using the arrayContainsAny instead of EqualTo in your where clause.
Like this:
final filteredDocuments = collectionRef.where('users', arrayContainsAny: [
authUserRef,
chatUserRef
]);
I'm making a product display app.
I'm going to create a "Wish List" widget that brings up the product that the user picked as 'wish item'.
I structured it as shown in picture 1.
And to create a widget,
I get all the documents of the collection('wish') of doc('User A').
And with their String values(product name) of the doc,
Get the product data from the collection ('Product') using Query.
The product collection is shown in the picture below.
Is there a more efficient way?
I thought it might be easier to change the data structure.
However, even if I create a new Collection('Wish'), at the same level as Collection('Product'), and put the product's name and user's e-mail in it,
I need to focus on the 'Product' collection with the 'Product name'.
Because I have to use the price, brand, name of product, in Collection('Product').
Is there any other efficient way I'm missing? Thank you!
Instead of storing the product name in string you can use reference type to store direct reference of the document inside other document.
Example code
DocumentReference ref = db.collection('products').doc('product-document-id');
Map<String,dynamic> data = {
'name' : 'Product A',
'product_ref' : ref, // Product document Reference
};
db.collection("users")
.doc("user-id")
.collection("wish")
.doc("your_product_name")
.set(data);
This will add the wish product with dynamic id.
Now you can directly read the document using the product_ref. You can use something like this
final docRef = db.collection("users")
.doc("user-id")
.collection("wish").doc("your_product_name");
final docSnapshot = await docRef.get();
if (docSnapshot.exists) {
final data = doc.data() as Map<String, dynamic>;
var productRef = data?['product_ref'];
productRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
// you will get your product here
}
});
}
I'm trying to get only one document from the collection.
I have Collection named cards, in this collection I've created Documents with Auto ID, each Document have field Name. In one of the documents fild Name = Horse.
How can I retrive this document and all the fields related to it?
The problem that I've faced is that all of the documentation relay on listviews. In my case I don't have a need and use of listview.
Try this:
final colRef = Firestore.instance.collection("your_path");
final snapshot = await colRef.where("Name", isEqualTo: "Horse").limit(1).getDocuments();
final docSnapshot = snapshot.documents[0];
Is there a way to achieve this?
i have tried to assign the entry to a local variable but it doesn't work with crudmethods.
getData() async {
String userId = 'userId';
Firestore.instance.collection('user').document(userId).snapshots();
var snapshot;
var userDocument = snapshot.data;
String _myAddress = userDocument["address"];
return Firestore.instance
.collection('letters')
.where("source Box", isEqualTo: _myAddress)
.snapshots();
}
Yes, you should be able to use a document in the query of another document.
For this, you need to create a reference for one collection and use it in another one.
The below code is an example that you can give it a try adapting further for your case, but that I believe should help you.
// Create references to the profile and orders collections
var profilesRef = db.collection("profile");
var ordersRef = db.collection("orders");
// Create a query against the collection.
var query = ordersRef.where("username", "==", ).doc("username").get();
In the documentation Perform simple and compound queries in Cloud Firestore, there is more information and example of queries that should help you.
In addition to that, this below post from the Community can provide you some insights on how to achieve this type of query as well.
How can I get specific document data from firestore querysnapshot?
Let me know if the information helped you!