Firestore "where" query not working as expected - javascript

I am trying to do a simple query from my firestore data base but I am missing something very obvious. I tried looking online but nothing works. For some background, I have a "cf" collection where I am trying to query a the objects that have the "hsc" value equal to "1" but I don't get anything in return.
exports.getOneTodo = (request, response) => {
db
.collection('cf')
.where("hsc", "==", "1")
.get()
.then((doc) => {
if (!doc.exists) {
return response.status(404).json(
{
error: 'Todo not found'
});
}
TodoData = doc.data();
TodoData.todoId = doc.id;
return response.json(TodoData);
})
.catch((err) => {
console.error(err);
return response.status(500).json({ error: error.code });
});
};
Below are the firestore rules.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write
}
}
}
I am testing this via the postman. I have tried changing the firebase rules to be true for anything but still, nothing seems to be working.
UPDATE:
The following is how I initialized my DB
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
module.exports = { admin, db };

Your code is expecting a single document, but it has to be prepared for the query to return multiple documents. When you run get() on a Query object, it's going to yield a QuerySnapshot object. As you can see from the API documentation, it doesn't have an exists property. A check for that property will always be "false". What you have to do instead is check the results to first see if there were any documents, then get the first one:
db
.collection('cf')
.where("hsc", "==", "1")
.get()
.then((qsnapshot) => {
if (qsnapshot.docs.length > 0) {
const dsnapshot = qsnapshot.docs[0];
// send the response using dsnapshot.data()
}
else {
// send the response saying nothing was found
}
})

now you need to use
db.collection("id").whereGreaterThan("field","value")
.whereEqualTo("field","value")
.whereLessThen("field","value")

Related

Error while deleting a value of element in mongoDB array using filter function?

I tried to find the solutions over here but unable to get success while using $pull as the array values I have does not contain `mongo_id'.
So the scenario is that , I am trying to delete the specific comment of the particular user which I am passing through query params. M
My mongo data looks like this:
Now I am making API Delete request like this : http://localhost:8000/api/articles/learn-react/delete-comment?q=1 on my localhost .
ANd finally my code looks like this:
import express from "express";
import bodyParser from "body-parser";
import { MongoClient } from "MongoDB";
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect(
"mongodb://localhost:27017",
{ useNewUrlParser: true },
{ useUnifiedTopology: true }
);
const db = client.db("my-blog");
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: "Error connecting to db", error });
}
};
app.delete("/api/articles/:name/delete-comment", (req, res) => {
const articleName = req.params.name;
const commentIndex = req.query.q;
withDB(async(db) => {
try{
const articleInfo = await db.collection('articles').findOne({name:articleName});
let articleAllComment = articleInfo.comments;
console.log("before =",articleAllComment)
const commentToBeDeleted = articleInfo.comments[commentIndex];
//console.log(commentToBeDeleted)
// articleAllComment.update({
// $pull: { 'comments':{username: commentToBeDeleted.username }}
// });
articleAllComment = articleAllComment.filter( (item) => item != commentToBeDeleted );
await articleAllComment.save();
console.log("after - ",articleAllComment);
//yaha per index chahiye per kaise milega pta nhi?
//articleInfo.comments = gives artcle comment
res.status(200).send(articleAllComment);
}
catch(err)
{
res.status(500).send("Error occurred")
}
},res);
});
I have used the filter function but it is not showing any error in terminal but also getting 500 status at postman.
Unable to figure out the error?
I believe you'll find a good answer here:
https://stackoverflow.com/a/4588909/9951599
Something to consider...
You can use MongoDB's built-in projection methods to simplify your code.
https://docs.mongodb.com/manual/reference/operator/projection/positional/#mongodb-projection-proj.-
By assigning a "unique ID" to each of your comments, you can find/modify the comment quickly using an update command instead of pulling out the comment by order in the array. This is more efficient, and much simpler. Plus, multiple read/writes at once won't interfere with this logic during busy times, ensuring that you're always deleting the right comment.
Solution #1: The recommended way, with atomic operators
Here is how you can let MongoDB pull it for you if you give each of your comments an ID.
await db.collection('articles').updateOne({ name:articleName },
{
$pull:{ "comments.id":commentID }
});
// Or
await db.collection('articles').updateOne({ name:articleName, "comments.id":commentID },
{
$unset:{ "comments.$":0 }
});
Solution #2 - Not recommended
Alternatively, you could remove it by index:
// I'm using "3" here staticly, put the index of your comment there instead.
db.collection('articles').updateOne({ name:articleName }, {
$unset : { "comments.3":0 }
})
I do not know why your filter is erroring, but I would recommend bypassing the filter altogether and try to utilize MongoDB's atomic system for you.

Retrieve an array from a Firestore document and store it to Node.Js then use it as tokens to send notifications

I've been trying to figure this out for hours and I just can't. I'm still a beginner with Node.js and Firebase. I need your help to be able to retrieve the tokens array in my "userdata" collection to Node.js and be able to use it to send notifications in the Cloud Function. So far this is what I've been working on. Here is what my database looks like:
The receiverId is gathered from when I have an onCreate function whenever a user sends a new message. Then I used it to access the userdata of a specific user which uses the receiverId as their uid.
In the cloud function, I was able to start the function and retrieve the receiverId and print the userToken[key]. However, when I try to push the token it doesnt go through and it results in an error that says that the token is empty. See the image:
Your help would mean a lot. Thank you!
newData = snapshot.data();
console.log("Retrieving Receiver Id");
console.log(newData.receiverId); //uid of the user
const tokens = [];
const docRef = db.collection('userdata').doc(newData.receiverId);
docRef.get().then((doc) => {
if (doc.exists) {
console.log("DocRef exist");
const userToken = doc.data().tokens;
for(var key in userToken){
console.log(userToken[key]);
tokens.push(userToken[key]);
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error) => {
console.log("Error getting document:", error);
});
//Notification Payload
var payload = {
notification: {
title: newData.sendBy,
body: 'Sent you a message',
sound: 'default',
},
data: {
click_action : 'FLUTTER_NOTIFICATION_CLICK',
route: '/telconsultinbox',
}
};
console.log("Sending Notification now.");
console.log(tokens);
try{
//send to device
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
console.log(newData.sendBy);
}catch(err){
console.log(err);
}
I think you should avoid using for..in to iterate through an array (you can read more about it in this answer). Try one of these 2 options:
You could use forEach(), which is more elegant:
userToken.forEach((token) => {
console.log(token);
tokens.push(token);
});
for-of statement:
for(const token of userToken){
console.log(token);
tokens.push(token);
}
Also, I would consider renaming userToken to userTokens, since it should contain multiple values. Makes the code a bit more readable.

firestore set/add functions not working and promise is never resolved

Calling set on a doc or calling add function on a collection, never returns any response or error, and I can also not see any changes in the Firebase console. Although, read operations work fine and I can get data using get() on a collection.
const db = firebase.firestore();
const data = {
name: 'Product2',
sku: 'sku',
};
console.log('here before');
db.collection('stores').doc('store1')
.collection('products').doc('YOigFkuBVFk70SSlXz9g')
.set(data)
.then((res) => {
console.log(res);
dispatch(slice.actions.setProducts([]));
})
.catch((e) => {
dispatch(slice.actions.setProducts([]));
console.log(e);
});
Here are the rules from the Firebase console:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true
}
}
}
Upgraded to version 9, and the issue is fixed.

Cloud Function Cannot Read Property of Undefined

New to Cloud Functions and trying to understand my error here from the log. It says cannot read property 'uid' of undefined. I am trying to match users together. onCreate will call matching function to check if a user exists under live-Channels and if so will set channel value under both users in live-Users to uid+uid2. Does the log also say which line the error is from? Confused where it shows that.
const functions = require('firebase-functions');
//every time user added to liveLooking node
exports.command = functions.database
.ref('/liveLooking/{uid}')
.onCreate(event => {
const uid = event.params.uid
console.log(`${uid} this is the uid`)
const root = event.data.adminRef.root
//match with another user
let pr_cmd = match(root, uid)
const pr_remove = event.data.adminRef.remove()
return Promise.all([pr_cmd, pr_remove])
})
function match(root, uid) {
let m1uid, m2uid
return root.child('liveChannels').transaction((data) => {
//if no existing channels then add user to liveChannels
if (data === null) {
console.log(`${uid} waiting for match`)
return { uid: uid }
}
else {
m1uid = data.uid
m2uid = uid
if (m1uid === m2uid) {
console.log(`$m1uid} tried to match with self!`)
return
}
//match user with liveChannel user
else {
console.log(`matched ${m1uid} with ${m2uid}`)
return {}
}
}
},
(error, committed, snapshot) => {
if (error) {
throw error
}
else {
return {
committed: committed,
snapshot: snapshot
}
}
},
false)
.then(result => {
// Add channels for each user matched
const channel_id = m1uid+m2uid
console.log(`starting channel ${channel_id} with m1uid: ${m1uid}, m2uid: ${m2uid}`)
const m_state1 = root.child(`liveUsers/${m1uid}`).set({
channel: channel_id
})
const m_state2 = root.child(`liveUsers/${m2uid}`).set({
channel: channel_id
})
return Promise.all([m_state1, m_state2])
})
}
You are referring to a very old version of the Cloud Functions API. Whatever site or tutorial you might be looking it, it's showing examples that are no longer relevant.
In modern Cloud Functions for Firebase, Realtime Database onCreate triggers receive two parameters, a DataSnapshot, and a Context. It no longer receives an "event" as the only parameter. You're going to have to port the code you're using now to the new way of doing things. I strongly suggest reviewing the product documentation for modern examples.
If you want to get the wildcard parameters as you are trying with the code const uid = event.params.uid, you will have to use the second context parameter as illustrated in the docs. To access the data from snapshot, use the first parameter.

firebase / firestore docs queries Not working - javascript

As firestore is new, i am having problems using it.
I have to get Collection of all users and traverse it. But it is not working.
db.collection("users").get().then(function(querySnapshot){
console.log(querySnapshot.data());
});
It says:
querySnapshot.data is not a function
And following code:
callFireBase(mobileToCheck){
db.collection("users").where("mobile_no", '==', mobileToCheck).get().then(function(querySnapshot){
if (querySnapshot.exists) {
var userData = querySnapshot.data();
var userId = querySnapshot.id;
console.log(mobileToCheck + "Exist In DB");
}else{
console.log(mobileToCheck + "Do Not Exist In DB");
}
});
}
Is always printing
923052273575 Do Not Exist In DB
Even if it exists, See following image for reference. In docs they have told this (i have used) way.
It looks that tou want to call.data() on collection of documents, not one document. Please see if this code works:
db.collection("users").get().then(function(querySnapshot){
querySnapshot.forEach(doc => {
console.log(doc.data());
});
}).catch(err => {
console.log('Error getting documents', err);
});
You should use docs.map then doc.data(). Here is how to do it with Firestore using async await syntax
import firebase from 'react-native-firebase'
async fetchTop() {
const ref = firebase.firestore().collection('people')
const snapshot = await ref.orderBy('point').limit(30).get()
return snapshot.docs.map((doc) => {
return doc.data()
})
}

Categories