Flutter Firebase Firestore Queries with Document Fieldpaths with maps - firebase

I am trying to sort a list of documents based on whether another user has seen it or not.
My database structure is the following:
following (Document Field){
Dy2k9f2m7uXnnBBPHssPxJucCrK2 : true (Map)
HOIXdQkoerRBgYCGHFRylQD2VKi1 : true (Map)
}
I tried running this command
print(
user.data()['following'].toString(),
);
and recieved the output
{HOIXdQkoerRBgYCGHFRylQD2VKi1: true, Dy2k9f2m7uXnnBBPHssPxJucCrK2:
true}
But I want to know whether a specified user id say HOIXdQkoerRBgYCGHFRylQD2VKi1 has the value true or false.
How do I go about it? Any help is greatly appreciated.

Firestore map type fields accessed with user.data()['following'] return a Map<String, dynamic>, so you can treat it like any other Map in dart. If you want to assume it contains bool values:
Map<String, bool> following = user.data()['following'];
bool seen = following['the-user-id-to-check'];

As Doug suggested, The issue here is that the value is probably dynamic.
You can cast it to a bool variable :
bool see = false;
String userKey = "Dy2k9f2m7uXnnBBPHssPxJucCrK2"; // <-- User Key
print(
see = user.data()['following'][userKey] as bool, // <-- cast as bool
);

Related

How to get document id from firestore

I'm trying to get my every document id in of my collection "meinprofilsettings". But I'm a bit struggling with that so maybe anyone can help.
First here's my code:
List<String> alluserids = [];
getHashtags() async {
final ref = FirebaseFirestore.instance;
QuerySnapshot snapshots = await ref.collection('meinprofilsettings').get();
for (QueryDocumentSnapshot idofuser in snapshots.docs) {
allVideoHastags.addAll(idofuser.id);
}
}
And then here's the error I get:
The argument type 'String' can't be assigned to the parameter type 'Iterable'.
This is a screenshot of my database:
I I just want every id of of every doc inside the list alluserids.
Perhaps you want to change this
allVideoHastags.addAll(idofuser.id);
To this:
alluserids.add(idofuser.id);
addAll method receives an Iterable as parameter. You want to add a single value so you should use .add
Also, you could use the .map method instead of for in:
allVideoHastags.addAll(snapshots.docs.map((idofuser)=>idofuser.id));
The behavior behind the last statement is that map returns an Iterable which has a value for each value that the base Iterable (in this case, your docs) contains.
In this case, the base iterable is snapshots.docs and our mapping returns Iterable<String> as we're returning every doc id. Hope this is enough for helping

How to query an array of objects in a Firebase Cloud Function, to get a matching object and then update

I am using a scheduled task in a Firebase Cloud Function to query an array which contains a number of objects that need to be updated if a matching condition exists. My current attempt is using the 'array-contains' method to get the objects, then loop over them to find a matching condition which will then batch update the items. This is my data structure:
I need to find an object that is <= the current time, and also if the 'active' value = false.
export const liveMeetingsTrigger = functions.runWith( { memory: '1GB' }).pubsub
.schedule('every 1 minutes').onRun(async context => {
const now = admin.firestore.Timestamp.now();
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
const batch = admin.firestore().batch();
liveMeetings.forEach(doc => {
if(doc.data().liveMeetingDate <= now && doc.data().active == false){
batch.update(doc.ref,'active',true);
}
});
return await batch.commit();
});
I have also tried using an exact object in the query instead of just using 'liveMeetingDate', but still get no results back, any help would be great - thanks.
Debugging: As the array I am trying to reach is inside of the (map) object 'liveMeetings' i have tried the dot notation (liveMeetings.meeting) with no success. Also trying a new collection with the the 'meeting' array at top level has provided no success.
Simple logging in the console (liveMeetings.size) shows that nothing is being returned on the query, so therefore the logging does not even reach the loop in the code.
As explained in this anwser the following query will not work:
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
because the meetings array contain some objects, instead of "simple" or primitive data (e.g. string, number...).
You could query it with the exact objects, like:
const obj = {active: false, liveMeetingDate: ..., meetingId: ..., ....};
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'obj').get();
Another approach would be to create a new collection which contains the similar documents (same Document ID) but with a meeting Array that contains only the liveMeetingDate property.
Finally, note that since your Array is within a map, you need to do
await admin.firestore().collection('fl_content').where('liveMeetings.meeting', 'array-contains', ...).get();
(PS: I don't mark this question as duplicate since you expressly ask for more help in the comments of the duplicate question/answer)

Firestore: Getting a subcollection from a DocumentSnapshot

I'm using Firestore for backend for a Flutter project, and the database is nested to have sub-collections under documents.Here's the structure:
I have the data found from the Root collection, and from there I'm trying to get the sub-collection, but I can't figure how to.
There should be a get() method available but I'm not getting any.
Here's the code for the function:
void _getNext(DocumentSnapshot doc) async {
int v = doc.data.length;
String id = doc.documentID;
print('length = $v \t id= $id');
await doc.reference.get().then((val){
val.data.forEach((k, v){
print('k = $k & v = $v');
});
});
await doc.data.forEach((k,v){
print("new k = $k, v = $v");
});
await doc.reference.collection(id).getDocuments().then((val){
val.documents.forEach((e){
print("another k = $e");
});
});
}
And the only response I get from pressing the "Literature" document (from the root collection) is this:
I/flutter (13395): length = 0 id= Literature
There are several sub collections to this document but the returned length is zero. The other blocks of code work fine when I added dummy data to the fields, but that's not needed in my case.
Thank You for your help.
collection() returns a CollectionReference. As you can see from the API docs, neither CollectionReference, nor it superclass Query have a method called get(). I suspect you want to use getDocuments() instead.
There is no get() method for CollectionReference, you need a DocumentReference.
There is nothing wrong with the current situation, you probably want to use getDocuments() since there are no subcollections under your collection, but documents
Notice the alternating pattern of collections and documents. Your collections and documents must always follow this pattern. You cannot reference a collection in a collection or a document in a document.
from: Hierarchical Data

How to pass a collection name as an argument into methods in Meteor?

Thanks my poor English skill, I have o express my idea by these code below..
Friendly edit:
I am trying to write a generalized confirmAndRemoveCollection method which takes in the collectionName and itemId, and I would like to perform operations on this collection. Since collectionName is a string, I wouldn't be able to perform DB operations on it. Could someone please suggest how I could use the collection name to get access to the actual collection object.
confirmAndRemoveCollection:(collectionName,itemId)->
check(itemId,String)
check(collectionName,String)
sweetAlert({
title:"confirm"
text:"blabla"
type:"info"
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "delete"
cancelButtonText: "cancel"
closeOnConfirm: false,
},(isConfirm)->
if isConfirm
collectionName.remove(itemId)
else
return
swal(
'success'
"selected item deleted"
"success"
)
The variable collectionName is a string object, so you won't be able to call MongoDB methods on it.
One way to accomplish your task is to create an object that maps the string name to the collection object.
For example:
Posts = new Mongo.Collection('posts');
Comments = new Mongo.Collection('comments');
Collections = {
'Posts': Posts,
'Comments': Comments
};
Then you could do something like this in your code
if isConfirm
Collections[collectionName].remove(itemId)
Just to add an alternative here (even though the question is really old): you can pass the collection itself as an argument and it will work.
As the collection is an Object, when you pass it as an argument it will be passed "by reference" and you will be able to call its methods.
Following the example by #FullStack (which also works, of course):
Posts = new Mongo.Collection('posts');
Comments = new Mongo.Collection('comments');
const collectionRemove = (collection, id) => {
const count = collection.remove(id);
console.log(`Removed ${count} items with id ${id} from collection ${collection._name}`)
}
And then do something like:
collectionRemove(Posts, 1);
collectionRemove(Comments, 24);

filtering collection from backbone with attributes

I've got a backbone collection and I'm trying to filter by an id within the attributes
basically, a user has classes, and the class has a location_id, and I want to filter by the location id. My collection looks like this to give you an idea.
-user
-models
-0
-attributes
-location_id
-1
-attributes
-location_id
-2
-attributes
-location_id
I thought I could filter this by using
var get_locations = user_class_collection.filter(function(classes){
console.log(classes);
return classes.get(location_id)==location.id;
});
console.log(get_locations);
but that is returning an empty array, when I know the location_id is in the collection.
Any idea why this isn't working? I've also tried to grab classes.attributes.get, but it wasn't any better
In the first few responses, it was properly mentioned that I had to quote the get('location_id'). I've now done that, but unfortunately, I'm still getting an empty array. I thought that the filter would loop through the classes and I would get a console output for each class, but the console.log(classes) is only getting triggered once. Is that a hint? Or a red-herring?
you are trying to get a property from classes that is named as the value of the location_id parameter
you should instead make that a string (in fact you can choose how you make it a string, single or double quotes both work)
user_class_collection.filter(function(classes){
return classes.get('location_id') == location.id;
});
For filtering collection using backbone the best approach is to use a filtered function in your collection
var UserCollection = Backbone.Collection.extend ({
filtered : function ( id ) {
I suggest to use UnderScore filter which will return true for valid and false for invalid where true is what you are looking for. use this.models to get the current collection models use model.get( '' ) to get the element you want to check for
var results = _.filter( this.models, function ( model ) {
if ( model.get('location_id') == id )
return true ;
return false ;
});
Then use underscore map your results and transform it to JSON like
results = _.map( results, function( model ) { return model.toJSON() } );
Finally returning a new backbone collection with only results
return new Backbone.Collection( results ) ;
Optionally if you don't want to keep all the data in the collection but just the filtered one you should reset the collection and skip the above return like
this.reset( results ) ;
View call the filtered collection and the render the result
Try this:
user_class_collection.select(function(classes){
return classes.get("location_id")==location.id;
});

Resources