Check if a key is in gun.js - javascript

For example, before I put something in the database I want to check if that entry is already there.
I try to do this:
gun.get('demograph').once((data, key) => {
console.log("realtime updates 1:", data);
});
but I didn't get a response if 'demograph' is or not in the database( for example to get true or false) I just get the result.
I also tried to use .not from extensible API but I is not working.
Anyone has any idea how to check if an entry is already in the database?

I'm not a user of Gun but from what I see in the doc https://gun.eco/docs/API#-a-name-get-a-gun-get-key-
get allows a second argument callback where you can test for not found
gun.get(key, function(ack){
if(ack.err){
server.log(error)
} else
if(!ack.put){
// not found
} else {
// data!
}
})

Related

How to check all documents in a collection for a value firestore reactjs

Here is my code:
function loginHandler() {
firestore.collection("users").forEach(user => {
if (user.username === queryUsername && user.password === queryPassword) {
navigate("/");
}
else {
setMode("INCORRECT")
}
})
}
I am trying to check if a doc in the users collection of my firestore db has the username property of the queryUsername and the password property of the queryPassword.
When I run this function:
function loginHandler() {
if (firestore.collection("users").doc("doc that definetly doesnt exist")) {
console.log("exists")
}
else {
console.log("doesnt exist")
}
}
It logs exists for some reason
1. Starting with the second code snippet
firebase.collection("someCollection").doc("some docID which might exist or not")
The code above returns an object or snapshot according to firebase which gives you informations about the document you are looking up whether it exists or not. By code implication your code will always return the document exist since an object passed to an if statement is always true. From firebase official documentation this will be the way to solve this
firebase.collection("SomeCollection").doc("some document ID which exists or not").get()
.then((user)=>{
if(user.exists){
console.log("exists");
} else{
console.log("doesn't exists");
}
})
2. From the First code snippet
SOME NOTES
From the looks of things you want to perform some kind of authentication, though storing users real password is highly risky and a bad practice, if you want to store password you can hash them, but for illustration purpose i will use your code sample.
The first code snippet gets all document from firebase database and do the checking on the client side, this is inefficient and will not be a good practice assuming your collection size goes to infinity, i will attempt to fix your code and then provide a better solution
Your Code Solution
When you read a firebase collection what you get is a snapshots of documents, you have to call .data() on each snapshot to get the actual document stored on firebase. Your code solution will now be like this asuming usernames and passwords are stored raw
function loginHandler() {
firestore.collection("users").get().then(users => {
users.forEach((user)=>{
if (user.data().username === queryUsername && user.data().password === queryPassword) {
navigate("/");
}
else {
setMode("INCORRECT")
}
})
})
}
The Efficient
The most efficient way is to run this codes from database level, in that case you dont have to accumulate costs as your app grows for document reads.
firestore.collection("users").where("username","==",queryUsername)
.where("password","==",querypassword).limit(1).get()
.then((result)=>{
if(result.exists){
console.log("do something after users creds are ok")
}else{
console.log("do something if not ok")
}
})
Note from the answer you have to create a compound index of username and password field in your firestore console check it out here
Not the limit i used is intentional so i can return only one document that matches and call .exists on the snapshot else it will return array of snapshots even if only one document can be found.

I want to make sure the Post Is Not Liked multiple times by The same user using Firebase

I have these codes to make the Like functionality
/*Here I increment by 1 every time someone submit like*/
db.collection("post").doc(postId).update({
likes: increment
})
/*Here I collect the uid of the user who submit Like and append to an Array*/
db.collection('post').doc(postId).update( {
usersArray: firebase.firestore.FieldValue.arrayUnion( userId )
});
now is possible to have code that runs every time someone submits Like to check if the user already exists in the usersArray?
Before updating the post document, you first need to read it in order to check if userId is already included in the usersArray array.
For that you shall use a Transaction to ensure that the document was not modified between the time you read it for checking the Array and the time you update it.
const postDocRef = db.collection('post').doc(postId);
return db
.runTransaction((transaction) => {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(postDocRef).then((postDoc) => {
if (!postDoc.exists) {
throw 'Document does not exist!';
}
if (postDoc.data().usersArray.includes(userId)) {
throw 'User has already liked this post!';
}
const newLikes = postDoc.data().likes + 1;
transaction.update(postDocRef, {
usersArray: firebase.firestore.FieldValue.arrayUnion(userId),
likes: newLikes,
});
});
})
.then(() => {
console.log('Transaction successfully committed!');
})
.catch((error) => {
console.log('Transaction failed: ', error);
});
Keep in mind that even with this code, malicious users can still use your configuration data with their own code to write their UID into the array a second time. To prevent this, you'll want to write security rules to only allow adding the UID if it isn't in the array already (by comparing request.resource with resource).
Use cloud functions for counter increments like post likes.We can get updated and previous value of document in onUpdate function trigger on post collection,then we can check if user is already included in userArray and increment/decrement like count accordingly.

Cannot get the full json with request json

When I am actually entering the XXXX YYYY, then I am getting the players json code in my html page (around 150 values).
But when I am trying to use a function on the players list it somewhy does not contain all the 150 values and the try throws me into the catch error part, where I can see that players json has only 100 players inside there.
Any idea what could be the problem?
if(yourID === "XXXX" && targetID === "YYYY"){
return players;
}
try{
if(isUserAlive(yourID)){
if(targetID === ""){
return userTargetInfo(yourID);
}
var checkForMatch = getUserTarget(yourID);
if(checkForMatch === targetID){
killTarget(targetID);
getUser(yourID).targetID = getTargetTarget(targetID);
addScore(yourID);
return userTargetInfo(yourID);
//return getTargetTargetStats(targetID);
}else{
return "INVALID";
}
}else{
return "DEAD"
}
}catch(err){
console.log("Error",console.log(players))
return "INVALID"
}
Edit: Since I had no time, I created 2 websites and divided the database into 2 different databases, so it would work under 100 people on each. Did not have time to fix the error at this point. So I won't be choosing the solution to that since I won't be trying that any time soon.
Thank you for all your help!
Check the link api that you are using , it might have pagination integrated with it . in that case i will return certain number of object 1st and then you can re-request to get next batch . Most likely they might have a option to change the no of object returned (sometimes with max value)
I'm pretty sure body is returned as a string. Try changing it to an object so you can work with it easier.
Change:
players = body;
to:
players = JSON.parse(body);
I'm not sure the rest of your code, but you may want to add var on your players variable declaration because this looks like the first time you are setting it.
Research: namespace collisions
If you are still having issues, edit your question to include the response you are getting from console.log(JSON.parse(body));. You will be able to get more helpful answers. Personally, I am curious to see the keys such as:
{ query:
{ count: 1,
created: '2017-04-23T22:03:31Z',
lang: 'en-US',
results: { channel: [Object] } } }
If it's paginated, you should see some kind of cursor key in there, or prev and next along with some kind of totalCount.
Hope this helps.

Firebase how to dynamically search for a push key under a user's data

{
"foo":{
"uid":{ // user's uid
"push_key_1":{
"bar":"baz"
},
"push_key_2":{
"bar":"baz"
}
}
}
}
Given the code model above, how do I dynamically search for the push_key_1 or push_key_2 in a query?
I've tried to do :
var searKey = 'push_key_1';
db.ref('foo').orderByKey().equalTo(searKey).once('value')
.then(function(snap){
// snap.val() returns null.
}).catch();
But the snap.val() is null. Turns out orderByKey() is for sorting purposes only. Is there a way to achieve this?
It's a lot simpler than what you're trying. When you know the key of the node you want to load, you don't need a query at all:
db.ref('foo').child(searKey).once('value'....
I think it's not possible unless you restructure the database. My approach is to add another node to store the push keys.
"users_push_keys": {
"push_key_1": "uid_1",
"push_key_2": "uid_1"
}
With this, you can get the uid by retrieving the data from this node.
Hope this helps :)

Firebase array item is removed and immediately auto-added back (with AngularFire)

I am trying to remove an item from $firebaseArray (boxes).
The remove funcion:
function remove(boxJson) {
return boxes.$remove(boxJson);
}
It works, however it is immediately added back:
This is the method that brings the array:
function getBoxes(screenIndex) {
var boxesRef = screens
.child("s-" + screenIndex)
.child("boxes");
return $firebaseArray(boxesRef);
}
I thought perhaps I'm holding multiple references to the firebaseArray and when one deletes, the other adds, but then I thought firebase should handle it, no?
Anyway I'm lost on this, any idea?
UPDATE
When I hack it and delete twice (with a timeout) it seems to work:
function removeForce(screenIndex, boxId) {
setTimeout(function () {
API.removeBox(screenIndex, boxId);
}, 1000);
return API.removeBox(screenIndex, boxId);
}
and the API.removeBox:
function removeBox(screenIndex, boxId) {
var boxRef = screens
.child("s-" + screenIndex)
.child("boxes")
.child(boxId);
return boxRef.remove();
}
When you remove something from firebase it is asynchronous. Per the docs the proper way to remove an item is from firebase, using AngularFire is:
var obj = $firebaseObject(ref);
obj.$remove().then(function(ref) {
// data has been deleted locally and in the database
}, function(error) {
console.log("Error:", error);
});
$remove() ... Removes the entire object locally and from the database. This method returns a promise that will be fulfilled when the data has been removed from the server. The promise will be resolved with a Firebase reference for the exterminated record.
Link to docs: https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebaseobject-remove
The most likely cause is that you have a security rules that disallows the deletion.
When you call boxes.$remove Firebase immediately fires the child_removed event locally, to ensure the UI is updated quickly. It then sends the command to the Firebase servers to check it and update the database.
On the server there is a security rule that disallows this deletion. The servers send a "it failed" response back to the client, which then raises a child_added event to fix the UI.
Appearantly I was saving the items again after deleting them. Clearly my mistake:
function removeSelected(boxes) {
var selectedBoxes = Selector.getSelectedBoxes(boxes);
angular.forEach(selectedBoxes, function (box) {
BoxManager.remove(box);
});
Selector.clearSelection(boxes, true);
}
In the clearSelection method I was updating a field on the boxes and saved them again.
Besides the obvious mistake this is a lesson for me on how to work with Firebase. If some part of the system keeps a copy of your deleted item, saving it won't produce a bug but revive the deleted item.
For those, who have the similar issue, but didn't solve it yet.
There are two methods for listening events: .on() and .once(). In my case that was the cause of a problem.
I was working on a migration procedure, that should run once
writeRef
.orderByChild('text_hash')
.equalTo(addItem.text_hash)
.on('value', val => { // <--
if (!val.exists()) {
writeRef.push(addItem)
}
});
So the problem was exactly because of .on method. It fires each time after a data manipulation from FB's console.
Changing to .once solved that.

Categories