I am using Firebase database with a Json structure to manage users' comments.
{
"post-comments" : {
"post-id-1" : {
"comment-id-11" : {
"author" : "user1",
"text" : "Hello world",
"uid" : "user-id-2"
},....
}
I would like to pull all the comments but excluding the current user's one.
In SQL this will be translated into:
Select * from post-comments where id !="user-id-2"
I understand that Firebase database does not offer a way to excludes nodes based on the presence of a value (ie: user id != ...).
Thus is there any alternative solutions to tackle this. Either by changing the Database structure, of maybe by processing the datasource once the data are loaded.
For the latter I am using a FirebaseTableViewDataSource. is there a way to filter the data after the query?
Thanks a lot
The first solution is to load the comments via .ChildAdded and ignore the ones with the current user_id
let commentsRef = self.myRootRef.childByAppendingPath("comments")
commentsRef.observeEventType(.ChildAdded, withBlock: { snapshot in
let uid = snapshot.value["uid"] as! String
if uid != current_uid {
//do stuff
}
})
You could expand on this and load everything by .Value and iterate over the children in code as well. That method will depend on how many nodes you are loading - .ChildAdded will be lower memory usage.
Related
I have a big collection with several thousand documents. These documents have subcollections with documents inside. Now I deleted a lot of the documents on the highest level.
Structure:
MyCollection => MyDocument => MySubcollection => MySubdocument
Now I realized, that the files are deleted (not showing up in any query) but the subcollections and their documents still exist. Now I am not sure how I can delete them as well, as I don't know the ID's of my deleted documents.
When I would try to find out the ID's by just sending a query to my collection to read all documents, the deleted ones are (by design) not included anymore. So how can I figure out their IDs now to delete their subcollections?
Thanks for any advice!
It all depends on your exact goal.
If you want to delete ALL the docs in the MyCollection collection, including ALL the documents in ALL the sub-collection, you can use the Firebase CLI with the following command:
firebase firestore:delete MyCollection -r
Do firebase firestore:delete --help for more options.
Of course, this can only be done by an Owner of your Firebase project.
If you want to allow other users to do the same thing from the front-end (i.e. ALL the docs, including ALL the sub-collections), you can use the technique detailed in the "Delete data with a Callable Cloud Function" section in the doc.
As explained in this doc:
You can take advantage of the firestore:delete command in the Firebase Command Line Interface (CLI). You can import any function of the Firebase CLI into your Node.js application using the firebase-tools package.
The Firebase CLI uses the Cloud Firestore REST API to find all documents under the specified path and delete them individually. This implementation requires no knowledge of your app's specific data hierarchy and will even find and delete "orphaned" documents that no longer have a parent.
If you want to delete ONLY a subset of the documents in the MyCollection collection together with the documents in the sub-collection, you can use the same methods as above, with the path to the documents, e.g.:
firestore:delete MyCollection/MyDocument -r
Finally, if your problem is that you have already deleted "parent" documents and you don't know how to delete the documents in the (orphan) sub-collections (since you don't know the ID of the parent), you could use a Collection Group query to query all the MySubcollection subcollections and detect if the parent document exists or not. The following code, in JavaScript, would do the trick.
const db = firebase.firestore();
const parentDocReferences = [];
const deletedParentDocIds = [];
db.collectionGroup('MySubcollection')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id);
console.log(doc.ref.parent.parent.path);
parentDocReferences.push(db.doc(doc.ref.parent.parent.path).get());
});
return Promise.all(parentDocReferences);
})
.then((docSnapshots) => {
docSnapshots.forEach((doc) => {
console.log(doc.id);
console.log(doc.exists);
if (!doc.exists && deletedParentDocIds.indexOf(doc.id) === -1) {
deletedParentDocIds.push(doc.id);
}
});
// Use the deletedParentDocIds array
// For example, get all orphan subcollections reference in order to delete all the documents in those collections (see https://firebase.google.com/docs/firestore/manage-data/delete-data#collections)
deletedParentDocIds.forEach(docId => {
const orphanSubCollectionRef = db.collection(`MyCollection/${docId}/MySubcollection`);
// ...
});
});
Now, I am trying to find specific user id by search by "phoneNumber" but his phoneNumber in specific node, so it's hard to reach or I don't know how I can find it. I want to get snapshot of this Info node.
Database structure
I am tried to search by query like that:
Query q=FirebaseDatabase.getInstance().getReference("Users")
.orderByChild("phoneNumber").equalTo("8#gmail.com");
```
and also tried this one
```
Query q=FirebaseDatabase.getInstance().getReference("Info")
.orderByChild("phoneNumber").equalTo("8#gmail.com");
But not worked also :(
None of those queries will work since in your first query you are missing the Info child and in the second you are missing the Users child. To solve this, please use the following query:
Query q = FirebaseDatabase.getInstance().getReference()
.child("Users")
.orderByChild("Info/phoneNumber")
.equalTo("8#gmail.com");
First things you need to do you have to make index in your firbase console rules
like this
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read" : true,
".write" : false,
"admin": {
".indexOn": "phone"
}
}
}
then write in you file where you are trying to get data by phone number
Query q=FirebaseDatabase.getInstance().getReference("Users")
.orderByChild("phoneNumber").equalTo("phoneValue")->getValue();
CONTEXT :
Hi, I'm currently working on an Android project backed by Firebase.
I have set up a denormalized data structure that relates polls to users (many-to-many relationship) via way of votes. Here is an image displaying the votes path of my database. The structure is as follows :
votes -> [pollUid] -> [votePushuid] -> vote object
So in this example we have a single poll that has 4 votes.
I want to run a check to see if a user has already voted on a poll. In order to do this I fetch the pollsUid, then run through its votes to see if any of them contain the voterUid property == to their user uid.
This is done as follows :
FirebaseHandler.getInstance().getMainDatabaseRef()
.child(FirebaseConstants.VOTES) //votes root
.child(pollKey) //polluid
.orderByChild("voterUid")
.equalTo(FirebaseHandler.getInstance().getUserUid())
.limitToFirst(1)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()) {
If the datasnaptshot exists then we know that the user has already voted on this poll and can handle it in the Java logic.
PROBLEM :
The datasnapshot received by onDataChange is always null (ie does not exist) when searching for a specific user's vote on a specific poll. I know for a fact that the vote exists in the db through inspecting the data, and that the userUid is correct via debugging. Removing the equalTo and limitToFirst returns all of the votes for the poll without a problem so clearly the stem of the ref is correct. This implies to me that the issue is created by one of the two methods just mentioned. Even stranger is the fact that this approach does work at certain times, but not at others.
QUESTION :
How do I return a list of firebase stored objects filtered by a grandchild property? If this is not possible what would be the more appropriate datastructure for this problem?
On a further note I've seen people taking the approach of using Query instead of Databasereferences. Perhaps this might have something to do with the current issue.
Your query is correct. I have no problem running that query using my own DB. It's probably the userId doesn't match. DatabaseReference extends Query, that's why you can access Query's methods.
A database structure alternative would be
{ "users_votes": {
"<userId>": {
"<pollId1>" : true,
"<pollId2>" : true,
"<pollId3>" : true
}
}
}
Set the value to that node once the user voted to a poll.
To check if the user has voted for a poll
usersVotesRef.child(FirebaseHandler.getInstance().getUserUid())
.child(pollKey).addListenerForSingleValueEvent(valueEventListener);
I've setup full text search and MongoDB and it's working quite well (Mongo 2.6.5).
However it does an OR instead of and AND.
1) Is it possible to make the query an AND query, while still getting all the benefits of full text search (stemming etc.)
2) And if so, is it possible to add this option via the Morphia wrapper library
EDIT
I see that the full text search includes a 'score' for each document returned. Is it possible to only return docs with a certain score or above. Is there some score that would represent a 'fuzzy' and query. That is usually all tokens are in the document but not absolutely always. If so this would solve the problem as well.
Naturally if possible to do this via Morphia that would be super helpful. But I can use the native java driver as well.
Any pointers in the correct direction, much appreciated.
EDIT
Code looks like this, I'm using Morphia 1.0.1:
Datastore ds = Dao.instance().getDatabase();
Query<Product> q = ds.createQuery(Product.class).search("grey vests");
List<Product> prods = q.asList();
Printing the query gives:
{ "$text" : { "$search" : "grey vests"}}
Note: I am able to do take an intersection of multiple result sets to create an AND query. However this is very slow since something like "grey" will return a massive result set and be slow at feeding the results back.
EDIT
I've tried to chain the search() calls and add a single 'token' to each call. But I am getting a run time error. Code becomes:
q.search("grey").search("vests");
The query I get is (which seems like it's doing the right thing) ...
{ "$and" : [ { "$text" : { "$search" : "grey"}} , { "$text" : { "$search" : "vests"}}]}
The error is:
com.mongodb.MongoQueryException: Query failed with error code 17287 and error message 'Can't canonicalize query: BadValue Too many text expressions' on server ...
at com.mongodb.connection.ProtocolHelper.getQueryFailureException(ProtocolHelper.java:93)
In my grails application, I want to display all the current entries of the second-level cache from all regions.
My code is as following :
def getCacheStats() {
StatisticsImpl stats = sessionFactory.statistics
for (regionName in stats.secondLevelCacheRegionNames) {
log.debug stats.getSecondLevelCacheStatistics(regionName).entries
}
}
However everything works fine as long as the region name is not org.hibernate.cache.StandardQueryCache (region used for Query Cache). In that case, an exception is thrown :
java.lang.ClassCastException: org.hibernate.cache.QueryKey cannot be cast to org.hibernate.cache.CacheKey
Having googling around, I didn't find any clues about how to display the list of entries of the cached query result sets associated with regions StandardQueryCache and UpdateTimestampsCache.
Could you please help me find a solution for this?
It's fairly complicated but this should get you further. You can access the query cache via the SessionFactory, so assuming you have access to that (e.g. via 'def sessionFactory') then you can get to the underlying caches like this:
def cache = sessionFactory.queryCache
def realCache = cache.region.#underlyingCache.backingCache
def keys = realCache.keys
for (key in keys) {
def value = realCache.get(key).value
// do something with the value
}
Note that the values will be a List of Long values. I'm not sure what the first one signifies (it's a large value, e.g. 5219682970079232), but the remaining are the IDs of the cached domain class instances.