Adding a collection to an existing document in Firestore - ionic-framework

I am trying to add a song to an album collection but I do not know how to access the document ID within the album collection. I have got so far with the code below but how does one access the doc id and represent it as a string. I want my database to as such:
Band > Album > Song
So that each band can have multiple albums and each album can have multiple songs. What do I reference in the .doc() for the albums collection?
Any help is greatly appreciated. Thank you
//Allow user to append a song to an album.
createSong(value){
return new Promise<any>((resolve, reject) => {
let currentUser = firebase.auth().currentUser;
this.afs.collection('band').doc(currentUser.uid).collection('albums').doc().collection('songs').add({
title: value.title,
description: value.description
})
.then(
res => resolve(res),
err => reject(err)
)
})
//console.log(value.id);
}

Related

how to get to a specific path on firestore?

i've added a field called like inside a document and i want to add many userId to the like array
uploading methode
var list=[];
await fearbase.collection("users").doc(widget.user)
.collection("PostData").doc(this.ido)
.set({"PostUrl":downloadUrl,"ownerName":loggedInUser.username,"userId":loggedInUser.uid,"timestemp":postId,"PostId":ido,"like":FieldValue.arrayUnion(list)})
.whenComplete(() => Fluttertoast.showToast(msg: "Image Uploaded successfully .i."));
// .then((DocumentReference ido) => ido.update({"PostId":ido.id}))
}
also in this methode (like) i want to add uid to the like array and also count them
Like methode:
void addLike(bool liked) {
// ##################################################
String ido=FirebaseFirestore.instance.collection("PostData").doc().id;
CollectionReference collectReef=FirebaseFirestore.instance.collection("users")
.doc(user!.uid).collection("PostData");
liked =!liked;
if(liked){
DocumentReference reef=collectReef
.doc();
reef.set({
'UserId':user!.uid,
// 'nameAR':loggedInUser.username,
// 'CreationTime':DateTime.now(),
});
```!
every document has his own id (each Post ) and every have fields one of those fields is like(array)
i want to put liked user (uid) in that specific path

How to arrange documents in Firestore using Flutter through custom document IDs?

I want to order the documents in Firestore. The default Firestore documents list consist of alphabetic characters which get created automatically. But I don't want that. I just want to see my newly added document added at the top of my documents list. How do I do that in flutter? It would be very helpful if you provide me with a code for that. The code I use to create a collection is:
Future<void> userSetup() async {
String user = FirebaseAuth.instance.currentUser?.displayName as String;
CollectionReference users = FirebaseFirestore.instance.collection(user);
final hours = time?.hour.toString().padLeft(2, '0');
final minutes = time?.minute.toString().padLeft(2, '0');
users.add({
"customerId": FirebaseAuth.instance.currentUser?.uid.toString(),
"customerName": FirebaseAuth.instance.currentUser?.displayName,
"customerEmail": FirebaseAuth.instance.currentUser?.email,
"selectedTime": '${hours}:${minutes}',
"selectedDate": DateFormat('dd/MM/yyyy').format(date!),
});
return;
}
But I am unable to set my own document id. Please help me with the issue. Thanks in Advance
From the Flutterfire documentation, the set() method is the one you should be using to be able to specify your own document IDs instead of add(). Keep in mind that if the document ID you specify already exists in your database, the whole existing document will be replaced. This is a sample usage as found in the documentation:
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
return users
.doc('ABC123')
.set({
'full_name': "Mary Jane",
'age': 18
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
It seems that documents are ordered alphabetically in the Firestore console, so your custom document IDs should follow alphabetical order as you require. Not to be confused with retrieving documents from Firestore in a particular order, which is done with the orderBy() method.

How can I set up a Stream for a subcollection in Firestore?

I have a Firestore database with the following structure:
usersCollection => user1 => productsHeldCollection => product1, product2, ...
I can set up a Stream for the userCollection, but am struggling to set one up for the productsHeldCollection which is a subcollection for each user. This is what I have tried.
First I created a reference for the subcollection:
final CollectionReference productsHeldCollection = Firestore.instance.collection('users').document().collection('productsHeld');
But I am not sure what to pass into the document() as I want it to be whatever the current user id is.
I then did the following:
List<ProductHeld> _productsHeldListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return ProductHeld(
productName: doc.data['Product Name'],
purchaseDate: doc.data['Purchase Date'],
expiryDate: doc.data['Expiry Date'], // these are fields within the subcollection
);
}).toList();
}
// Stream of products
Stream<List<ProductHeld>> get products {
return productsHeldCollection.snapshots().map(_productsHeldListFromSnapshot);
}
The names of documents within a collection are unique. You can provide your own keys, such as user IDs, or you can let Cloud Firestore create random IDs for you automatically.
The parameter you pass into the document() is the name of the document.
Google public documentation provides more details on how to design your hierarchical data structures to work in Cloud Firestore.

Firestore Subcollection '!=' query

I am aware Firestore doesn't support '!=' queries, but I was wondering if anybody has run into a similar situation as below:
Here is my db structure:
Posts -> postId -> postDocument -> likedBy -> uid
What I'm looking to do is only show posts that don't have the current user's uid in the 'likedBy' subcollection. That itself isn't possible, but I'm struggling to find even a semi-decent work around.
Currently I get all the posts and do the check locally to display the correct ones. Is this possible with perhaps a magic cloud function something?
You might find success and use cases beyond this one by maintaining a user's feed and then only calling that at runtime. I utilize this method and have found I'm given a lot of freedom and Cloud Functions let me dictate what types of posts show and under what changes are new posts added to a user's feed.
The way I do it is I look for new posts via an onCreate cloud function and then look up who should see that post, etc. and add it to each of their feeds.
In your case I can see it being used by looking for new likes on a post. On new likes, it can remove the post from the user's feed.
An example of a function (edited for brevity) that I use to add posts to the user's follower's feeds. By grabbing using a collectionGroup query I can query the list of all users who follow the author of the post.
The schema looks like this:
Users (collection)
--- User1 (document)
------- Following (collection of people User1 is following)
----------- FollowingUser1 (document, contains a uid of "followed" user)
----------- FollowingUser2
and the Cloud Function:
exports.newReview = functions.firestore
.document('reviews/{reviewId}')
.onCreate((snap, context) => {
var reviewId = context.params.reviewId
var reviewData = snap.data()
var userFollowers = db.collectionGroup('following').where('uid', '==', userId)
var followingTransaction = db.runTransaction(transaction => {
return transaction.get(userFollowers).then(restDocs => {
reviewData['added_via'] = 'following'
restDocs.forEach(doc => {
var followerId = doc.ref.parent.parent.id
var followerRef = db.collection(`feeds/${followerId}/posts`).doc(reviewId)
transaction.set(followerRef, reviewData);
})
return true
});
});
return followingTransaction.then(values => {
console.log(reviewData)
var shouldPostToTwitter = reviewData.postToTwitter
return Promise.resolve()
}) .catch(error => {
console.log(error)
return Promise.reject(new Error("Error deleting"));
});
});
DB look something look this:
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL
});
const db = admin.firestore()

Update Cloud Firestore Collection Based on "Master Collection"

I am creating an iOS application to help users who collect figurines keep track of their figurines and see realtime price information.
I have two collections:
The "master" collection
This is essentially a catalog of thousands of figurines users can select to add to their collection. It has information about each item, such as Artist, Original Price, Barcode, Year, Comments, etc.
The "user" collection
This contains documents for each user. Each of these "user" documents has a sub-collection with documents for each figurine they have added to their collection.
Currently, if a user wants to add a new item to their personal collection, they go to the "master" collection UITableView and swipe to add an item. The item document is basically copied from the "master" collection and a new document in the user sub-collection is created. They can then go to a UITableView that displays the items they have added. They have the option to add their own information about the item, such as comments, date bought, date sold, price bought, etc.
My question: How can I sync information between the document in the user collection/sub-collection and the document in the main collection? Say the "Market Price" for an item has gone up, so I update the main collection database. How can I get this price change to display in all users' collections?
I assume by using Cloud Functions, but I wanted to post here in case there was an easier method.
This is definitely a good use for Cloud Functions. Create an onUpdate trigger for your /users{uid}/figurines/{figurineId} collection and then use that to copy the updated data to the master.
You can either copy specific fields or you can check for differences by examining event.data.data() and event.data.previous.data()
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.updateMaster = functions.firestore
.document('users/{uid}/figurines/{figurineId}')
.onUpdate(event => {
var newData = event.data.data();
var oldData = event.data.previous.data();
var updateData = {};
if (oldData.price != newData.price) {updateData.price = newData.price}
// Add any more changes that you may want to compare / update below...
// Then...
return db
.collection('master')
.doc(event.params.figurineId)
.update(updateData).then(response => {
console.log('We updated figurine', event.params.figurineId);
}).catch(err => {
console.error('There was an error', err);
});
});