Firestore adds search conditions and cannot continue to monitor - ios

When the search condition is not added, the changes can be listened to in real time, but after I add the search condition, I cannot continue to monitor the changes. Why?
original code
db.collection("Users").document("pZOLUl9tyVdOKzyeUScIZ8BysPm1")
.collection("RechargeCoin")
.order(by: "date", descending: true)
.addSnapshotListener { (snapshot, error) in
Code after adding search criteria
db.collection("Users").document("pZOLUl9tyVdOKzyeUScIZ8BysPm1")
.collection("RechargeCoin")
.whereField("review2", isEqualTo: "未確認")
.order(by: "date", descending: true)
.addSnapshotListener { (snapshot, error) in
Modified code cannot listen for changes

Every query on Firestore needs an index that matches the exact fields that you order/filter on. When no such index exists, the query can't be executed and the SDK throws an error.
The behavior you're describing typically means that the necessary index is missing. You'll want to catch and log any errors coming from the Firestore API calls and then check in the error message for a URL. This URL takes you directly to the Firestore console in a page where you can create the necessary index with a single click (all fields will be prepopulated in the URL already).

Related

Check if a Firestore query (whereField isEqualTo) did find no documents

I want to check if my Firestore query did find any documents with the specific fields I want or not. If not I would like to proceed to some other code.
Unfortunately I haven't found a solution myself to this problem. Can you help?
Code:
Firestore.firestore().collection("conversations").whereField("mainUserID", isEqualTo: MainUID)
.whereField("otherUserID", isEqualTo: otherUserId).getDocuments { (snapshot, err) in
if snapshot.exists == true { // Value of type 'QuerySnapshot?' has no member 'exists'
} else {
}
}
From the docs
A FIRQueryDocumentSnapshot contains data read from a document in your
Firestore database as part of a query. The document is guaranteed to
exist and its data can be extracted with the data property or by using
subscript syntax to access a specific field.
A FIRQueryDocumentSnapshot offers the same API surface as a
FIRDocumentSnapshot. As deleted documents are not returned from
queries, its exists property will always be true and data: will never
return nil.
with the important bit being this
The document is guaranteed to exist
so therefore a .exists option would not make sense due to the guaranteed existence of the snapshot.
One approach is to check how many documents are in the snapshot
if docs.count > 0 {
//there are docs
} else {
//there are no docs
}

Swift Firebase database overwriting

I am making a real-time messenger using Firebase. Currently, whenever I press a button I want a new message to be appended to the channel with the index of the message, but currently, whenever I press the button a new message is created that overwrites the old message. I know that setValue is usually the issue, but I really cannot tell what I'm doing wrong. What the database looks like before I add my new message. This is what it looks like after I add a new message here, and then the code I am using to add to the database.
#IBAction func sendMessageTapped(_ sender: Any) {
if messageTextField.text == "" {
print("blank")
return
} else {
// First we will update the amount of messages that the channel has.
ref.child("channels").child(channelName!).setValue(["numberOfMessages" : numberOfMessages+1 ])
numberOfMessages += 1
// after we have updated the amount of messages we will try to create a new message.
ref.child("channels").child(channelName!).child("messages").child(String(numberOfMessages)).child("message").child("content").setValue(messageTextField.text)
ref.child("channels").child(channelName!).child("messages").child(String(numberOfMessages)).child("message").child("name").setValue("Buddy")
}
}
ok, Firebase is not a traditional table based database, is a DOCUMENT based database. At the very top you have a thing called a "collection" which is just a list of "document" things. In your case, you'd have several collection things to serve as channels: "General", "TopicQ", "InterstingStuff" etc, and within them each message as a document. No need to have a document, to then list the messages within it.
Second, you don't need indexes as you're using them, make the message id an attribute of the message, because firebase support querying by field, and even then is questionable because if you make each message a document, they will have their own auto generated id's if you want.
Third, in your code you're rewriting the whole document each time, this is why you lose your previous messages, so if you keep it, you need to add a merge option:
// Update one field, creating the document if it does not exist.
db.collection("cities").document("BJ").setData([ "capital": true ], merge: true)
you probably want to do something like this. This is what I did for my app, hope this helps someone. This rootRef.childByAutoId() generates a new entry with unique id. You can use this as reference for your case.
let rootRef = Database.database().reference(withPath: "channels")
let childRef = rootRef.childByAutoId()
let values = ["Type": self.textField.text!, "message": self.textView.text!] as? [String : Any]
childRef.updateChildValues(values)

Flutter Firebase Database wrong timestamp order

I'm trying to set timestamp into firebase realtime database but when I retrieve, not ordering by timestamp.
I did like so.
FirebaseDatabase.instance.reference().child('path').push().set({
'timestamp': ServerValue.timestamp
});
This is the node
Then I retrieve like so.
FirebaseDatabase.instance.reference().child('path').orderByChild('timestamp').once().then((snap) {
print(snap.value);
});
but output is this
{-LJhyfmrWVDD2ZgJdfMR: {timestamp: 1534074731794}, -LJhyWVi6LddGwVye48K: {timestamp: 1534074689667}, -LJhzDlvEMunxBpRmTkI: {timestamp: 1534074875091}
Those are not ordered by timestamp.
Am I missing something?
Otherwise is this firebase error or flutter?
The data is retrieved in the right order into a DataSnapshot. But when you call snap.value the information from the snapshot has to be converted into a Map<String, Object>, which not longer can hold information about the order of the child nodes.
To maintain the order, you have to process the child nodes from the DataSnapshot with a loop. I'm not an expert in Flutter (at all), but I can't quickly find a way to do this for a value event. So you might want to instead listen for .childAdded:
FirebaseDatabase.instance
.reference()
.child('path')
.orderByChild('timestamp')
.onChildAdded
.listen((Event event) {
print(event.snapshot.value);
})

How to extract the first row in a DynamoDB table?

I am using (AWS) DynamoDB for the first time, so my question is rather basic.
I have set up a table (myTable) containing one field (theField) and I am able to fill it up one record at a time.
Here is what I want to do: make a query to extract the first element of the sorted table. I guess it could hardly be simpler.
This is my code, based on what I could find in the AWS documentation and on some example from the net:
let queryExpression = AWSDynamoDBQueryExpression()
queryExpression.scanIndexForward = false
queryExpression.limit = 1
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDbObjectMapper.query(myTable.self, expression: queryExpression) {
(output: AWSDynamoDBPaginatedOutput?, error: Error?) in
if error != nil {
print("The request failed. Error: \(String(describing: error))")
}
if output != nil {
// Process the output.
}
}
When I run this code I get the error message below:
The request failed. Error: Optional(Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=0 "(null)"
UserInfo={__type=com.amazon.coral.validate#ValidationException, message=Either the KeyConditions or
KeyConditionExpression parameter must be specified in the request.})
First what is this KeyConditions or KeyConditionExpression business?
The query is clear why do I need any condition?
Second, I of course tried to fill some dummy condition (based on what I could find on some other post) to see what happens, but it never worked.
Could someone tell me how I need to write queryExpression to do what I want?
You have no query criteria. For a query you need to provide at least the PartitionKey. Try a scan instead of a query.
You cannot extract first item from a dynamodb. Not with scan or query. You have to scan the table entirely or create a GSI with createdAt as hashKey/sortKey

How to get all results from a Firebase Query in one block

I'm having a hard time working with Firebase query results. With the following code:
ref.queryOrderedByChild("gender")
.queryEqualToValue("female")
.observeEventType(.ChildAdded, withBlock: { snapshot in
print("result: \(snapshot) ")
})
The "result" is printed 3 times. I would expect a single array of all of the results (similar to a query on Parse) versus this being printed 3 separate times.
The end goal here is to append all of the results to an Array. However, I don't know how to do that, since I can't see any way of knowing how many elements will come back from the server.
I assume there must be something simple I am missing here.
It appears it was something simple I was missing. Changing the event type from .ChildAdded to .Value resolves the issue. Hopefully this will help someone else...
var resultArray:[AnyObject] = []
ref.queryOrderedByChild("gender")
.queryEqualToValue("female")
.observeEventType(.Value, withBlock: { snapshot in
for item in snapshot.children{
resultArray.append(item)
}
print("Results Array: \(resultArray)")
print("Results Array Count: \(resultArray.count)")
})

Resources