I have tried to use .indexOn of firebase on field 'status' which is inside the child of 'BOUGHT_PRODUCT'.
But, when i run following query.
db.ref().child('BOUGHT_PRODUCT')
.orderByChild('status')
.equalTo('Service')
.on("value", function (snapshot) {
console.log(snapshot.val());
});
I get null snapshots.
Even, Firebase warning of index :
"#firebase/database: FIREBASE WARNING: Using an unspecified index. Your data will be downloaded and filtered on the client. Consider adding ".indexOn": "status" at /BOUGHT_PRODUCT to your security rules for better performance."
Firebase Data:
Index firebase:
Your help would be appreciated.
Firebase Database queries run against each child under the location where you run them. The field you order/filter on must be at a fixed path under each child. Since you run the query on /BOUGHT_PRODUCT, the database searches for /BOUGHT_PRODUCT/$uid/status. And since that property doesn't exist, there are no results matching the query.
In other words: your current data structure allows you to query a specific user for the status of their products, but not across all users. If you want to implement that use-case, you will need to create a data model that allows it, e.g. a single top-level list of product statuses.
Statuses
product1: "Service"
product2: "Service"
product3: "Something else"
Also see:
Firebase Query Double Nested
Firebase query if child of child contains a value
Related
I have a small realtime firebase database that's set up like this:
database
-messages
--XXXXXXXXXXXX
---id : "XXX-XXX"
---content : "Hello world!"
It's a very simple message system, the id field is basically a combination of users id from my mysql database. I'm trying to return all messages that match one of the ids, either sender or receiver. But I can't do it, seems like firebase only support exacts querys. Could you give me some guidanse?
Here's the code I'm working with
firebase.database().ref("messages").orderByChild("id").equalTo(userId).on("value", function(snapshot)
I'm looking for something like ".contains(userId)"
Firebase supports exact matches (with equalTo) and so-called prefix queries where the value starts with a certain value (by combining startAt and endAt). It does not support querying for values that end with a certain value.
I recommend keeping a mapping from each user IDs to their messages nodes, somewhere separately in their database.
So say that you have:
messages: {
"XXXXXXXXXXXX": {
id : "YYY-ZZZ",
content : "Hello world!"
}
}
You also have the following mappings:
userMessages: {
"YYY": {
"XXXXXXXXXXXX": true
},
"ZZZ": {
"XXXXXXXXXXXX": true
}
}
Now with this information you can look up the messages for each user based on their ID.
For more on the modeling of this type of data, I recommend:
Best way to manage Chat channels in Firebase
Many to Many relationship in Firebase
this artcle on NoSQL data modeling
I have a Firebase (Real-time Database) node with a large number of children. I want to list all child keys, so I used this code:
reference.once('value', snapshot=>{
snapshot.forEach(child => {
console.log(child.key);
})
})
then Firebase will throw an exception:
The specified payload is too large, please request a location with less data.
So I don't know how to get the child keys (only keys) without getting that error. Please help!
Use Firebase's shallow query https://firebase.google.com/docs/database/rest/retrieve-data#shallow
For example, if your data is structured like this
parent: {
child_0: {...<large data>...},
child_1: {...<large data>...},
child_2: "abc",
child_3: 123
}
The shallow query's result will be:
parent: {
child_0: true,
child_1: true,
child_2: "abc",
child_3: 123
}
Some unexpected errors can send a cancel event and terminate the connection. The cause is described in the data provided for this event. Some potential causes are as follows: 1. The Firebase Realtime Database Rules no longer allow a read at the requested location. The data description for this cause is "Permission denied." 2. A write triggered an event streamer that sent a large JSON tree that exceeds our limit, 512MB. The data for this cause is "The specified payload is too large, please request a location with less data."
Since realtime database only limit 500Mb per request so in order to execute this request you should try to paging a query with or try to iterate over children using child_added listener instead of querying all of the childs.
This is the thing I want to accomplish: I'm building a web shop. The web shop has a React Front-end. The front-end fetches 5 collections from Firestore and displays all the items from the collection array on the shop page. A user selects an item on the shop page. I send the item fields such as (price, name, quantity, id) to my express server and the server makes a checkout session of the item fields. The user goes to a Stripe checkout form and is sent back to my front-end by Stripe when the payment is complete. I listen for that event on my server and when then want to update the quantity field of the item in Firestore.
But how do I query Firestore for this item? Is there a way to query Firestore with only this id field (or name field)? Some something like:
db
.collection('collections')
.where('id', '===', 1)
Or do I need to save the document id (of the collection) as a field inside the item map and also send that to Stripe? Or is there a better way to do this? I can't find anything online about this.
Here is a screenshot of Firestore.
Please forgive my beginner question. I'm still learning React, Firestore and Node.js.
First be sure you are sticking to the Firestore terminology correctly. There are collections and there are documents.
Collections you access via a path such as:
collRef = db.collection("products")
collRef = db.collection("products").where("quanity_on_hand", ">", "0")
collRef = db.collection("products").doc("12345").collection("purchase_history")
The latter instance can also be accessed via collRef = db.collection("products/12345/purchase_history").
In all the above cases you will get back a CollectionReference.
Documents you access such as:
docRef = db.collection("products").doc("12345")
docRef = db.doc("products/12345")
This returns you a DocumentReference for the document whose ID is "12345" in the collection "products".
So for your code example above, you want to use docRef = db.doc("collections/1") to get back the DocumentReference for the item you are after. (Or, alternatively, you could use: docRef = db.collection("collections").doc("1")
If you stick with the code that you have above, you'd get back a CollectionReference then you'd need to fetch the data with .get(), then extract the resulting documents (that will just be a single document), then work with that. Oh...and you will need to put an "id" field into all of your documents because the document's ID value (the "name" of the document) is not part of the document by default so if you want to use .where("id", "==", "1"), then you need to add an "id" field to your document and populate it correctly.
If you go with docRef = db.doc("collections/1"), you are querying for the document directly and will get back a reference to just that one. No need for extra fields, nor extracting a single document from a result set.
I am trying to achieve this for the friend request functionality in my data structure for sent requests, but I am unable to:
Essentially I am trying to pull this off from the Realtime Database in the Cloud firestore:
Above reqId1 and reqId2 are automatically generated Id's.
Its quite easy to pull this off in the Realtime db as I can just use the push() method.
The issue is not creating a random number, it is that I am unable to create a document with an autoID inside the userId document in which I shall store the data.
I have tried this:
sendRequest() {
const uid = auth().currentUser.uid;
firestore()
.collection('Sent_Reqs')
.doc(`${uid}`)
.collection(`${this.autoId()}`)
.add({
targetId: this.userId,
sentAt: new Date(),
});
}
But the above doesn't do any good because it nests the data two levels inside the document(uid).
Please help me
Thank you
The data structure on Firestore is always in pairs of collection and then document in there. The collection names are usually fixed/hard-coded names, while the document names are usually generated (or based on the data).
You can't immediately nest documents under another document, they must always be in a named collection. If there's no reason for you to have multiple subcollections, you can just pick any subcollection name that makes sense for you.
For example:
Sent_Requests
(uid)
Requests
(request_id)
Here Sent_Requests and Requests are collection names, (uid) and (request_id) are document names. The Requests collection is not really helpful, but needed to satisfy the Firebase requirements.
It's part of your document data. I don't this firebase can help you on that.
If you are structuring the database this way just to fetch the request sent by particular user easiy. I would like to suggest another structure as follows:
Sent_Request (collection)
|-AutoID1 (document, this ID you can generate with help of firebase)
|- targetUser : value
|- sentAt : value
|- requestSentBy : userId
|-AutoID2 (document, this ID you can generate with help of firebase)
|- targetUser : value
|- sentAt : value
|- requestSentBy : userId
In Firebase Firestore, I want to use orderBy twice. Do I need to create an index to speed up the query?
For example:
Query query = fsDB.collection("users").document(currentUID).collection("received_messages")
.orderBy("messageSeen").orderBy("date");
There is no automatic Error message that shows up like when using ranges or "where".
Structure looks like:
received_messages
date: 01/02/99
messageSeen: true
from: keuajopdf315
Should I put an index on the collection "received messages" and the "messageSeen" and "date" fields to speed up the query?
When I try to run a query with two orderBy() clauses, I get an error:
The query requires an index. You can create it here: ...
After adding the index that is linked in the error message, I can then retrieve the documents ordered-by-state-then-by-index. See my working jsbin here: https://jsbin.com/rewujav/edit?js,console
docs.orderBy("state").orderBy("index").get().then(function(snapshot) {
snapshot.forEach((doc) => {
console.log(doc.id+": state="+doc.data().state+" index="+doc.data().index);
})
})