how to use variable in firestore query - javascript

I use firebase firestore db. This project have two main collection "securecollection" and "publiccollection". The securecollection is where all important data is stored and only accessible to authenticated users. But in order for some information to be visible to guest users, I am copying them into the publiccollection. Then, I want to save the id of this newly created public document in the secure document.
When I write a variable
db.collection('securecollection').doc(secureDocid).update({ inside the query sentence, I get this error:
Uncaught (in promise) TypeError: o.indexOf is not a function
If I write the id as text db.collection('securecollection').doc('7llDqIWlmE5VM69Zzle2').update({, the code works.
Here is my code:
function toggleOlustur(secureDocid) {
const db = firebase.firestore();
db.collection("securecollection").get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
if (doc.id == secureDocid) {
db.collection("publiccollection").add({
oad: doc.data().oad,
osad: doc.data().osad,
opuan: doc.data().opuan,
odtarih: doc.data().odtarih,
odurum: "1",
})
.then((docRef) => {
db.collection('securecollection').doc(secureDocid).update({
preference: docRef.id
})
});
}
});
});
}

The doc() method expects a string argument, and from the error message it sounds like your secureDocid is not a string value. If you console.log(JSON.stringify(secureDocid)) you can see what it outputs, which might help to figure out the problem.

Related

How do you avoid missing data when using limit, orderBy, and startAfter with Firebase?

Isn't it true that you could miss data if what you are ordering by does not have a unique value?
For example if I have a function that says:
export async function getCities(){
const result = await firebase
.firestore()
.collection('cities')
.orderBy('population', 'desc')
.limit(5)
.get();
const CityResults = result.docs.map((city)=> ({
...city.data(),
docId: city.id
}));
if I limit to 5 and my last piece of data has a population of 1000, my getMoreCities() funciton would say
startAfter(1000)
But say there were 7 cities with a population of exactly 1000, you would miss the data on both of your firestore calls.
It seems silly you cant startAfter(documentId)
is there a workaround?
Firestore implicitly adds the document ID to each query where you specify an anchor document, so if you pass in a DocumentSnapshot it will already work.
You should also be able to pass the document ID as the last argument to your startAfter variant, although I must admit I always use the DocumentSnapshot for this purpose myself.
Here's an example of what this would look like:
citiesRef.orderBy("population").startAt(860000).limit(1).get().then((snapshot) => {
var lastdoc;
snapshot.forEach(function(doc) {
console.log("1: "+doc.id);
lastdoc = doc;
});
citiesRef.orderBy("population").startAfter(lastdoc).limit(1).get().then((snapshot) => {
snapshot.forEach(function(doc) {
console.log("2: "+doc.id);
lastdoc = doc;
});
});
});
Working version: https://jsbin.com/sibimux/edit?js,console

Trigger won't return the proper user object in Realm/MongoDB

With Realm sync of MongoDB, I'm trying to launch a trigger when a realm user is created to insert his newly created ID into my cluster. Here's the javascript function I made that is being called by the trigger :
exports = async function createNewUserDocument({ user }) {
const users = context.services
.get("mongodb-atlas")
.db("BD")
.collection("patients");
const query = { email: context.user.data.email };
const update = {
$set: {
patientId: context.user.id
}
};
// Return the updated document instead of the original document
const options = { returnNewDocument: true };
console.log(context.user.data.email);
return users.findOneAndUpdate(query, update, options)
.then(updatedDocument => {
if(updatedDocument) {
console.log(`Successfully updated document: ${updatedDocument}.`)
} else {
console.log("No document matches the provided query.")
}
return updatedDocument
})
.catch(err => console.error(`Failed to find and update document: ${err}`))
};
When running from the embed editor, while specifying the proper user manually, it's working perfectly. However, when launched by the trigger, it looks like the user is the system user and not the created user, because the error I get in the logs is the same I get when I run from the editor by specifying System user, which is Failed to find and update document: FunctionError: cannot compare to undefined. This makes sense because the System user is not a user per se, so the context.user is undefined.
I find it weird since I specify in the function settings that it should be executed with the permissions of the user calling the function. So my question is, is it possible to access the user.context of a user on his creation, and if so, how would I do it ?

How to listen firebase real-time changes into Reactjs?

I am creating a real-time chat application using firebase and React js. I create a const functions = require('firebase-functions');
called "chats" inside the firebase. This collection contains unique room_ID(a combination of sender and receiver) and that document again contains subcollections called "messages". Each collection inside the message has infomation like message, time, sender_id, and read status.
Now, every time, when I receive a new message into the chat list I have to update the conversation. I use componentDidMount() method of Reactjs and write below code:
firestore.collection('chats').doc("b7EuhNpdzXUlxhSgDkn2a6oReTl1_OZbrlH8FjmVFqSAtAc0A6TUHS3I3").collection("messages")
.onSnapshot(querySnapshot => {
console.log("querySnapshot", querySnapshot)
querySnapshot.docChanges().forEach(change => {
console.log("change", change)
if (change.type === 'added') {
this.setState({messages : [...this.state.messages, change.doc.data()]});
console.log('New city: ', change.doc.data());
}
if (change.type === 'modified') {
console.log('Modified city: ', change.doc.data());
}
if (change.type === 'removed') {
console.log('Removed city: ', change.doc.data());
}
});
});
You can see here that, It will only work for a single room(b7EuhNpdzXUlxhSgDkn2a6oReTl1_OZbrlH8FjmVFqSAtAc0A6TUHS3I3). I want to write query in such a way that it will listen to the message for each contact. For that, I have to remove the restriction of specific doc.
Please help me.
Thank you in advance.
Here is the structure of Firebase database.
Look into the documentation for CollectionGroups - set your listener to the .collectionGroup("messages") - you will have to process through the changes for all of the different "chats" documents. (HINT: each returned messages DocRef includes the refPath field - which you can trivially parse to find the path to the "parent" chat document)
I believe a few better approaches to fetch the data you want would be to either:
Restructure your Firestore to have only a messages collection, like the following example structure:
messages collection
uid
receiverUserId
senderUserId
msg
read
time
With this approach you could filter the documents you are watching, for example documents received by the currently authenticated user from multiple users, by doing something like this:
firestore.collection("messages")
.where("receiverUserId", "==", authUid)
.onSnapshot(function(querySnapshot) {
//do whatever
});
Create multiple listeners, one for each chats document, to watch it's subsequent messages subcollection. So you could do something like this untested code:
firestore.collection('chats').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
var eachChatRef = firestore.collection('chats').doc(doc.documentID)
var messagesRef = eachChatRef.collection("messages");
messagesRef.onSnapshot(function(snapshot) {
snapshot.docChanges().forEach(function(messageDoc) {
// Do whatever
});
});
});
});
To extend to #LeadDreamer answer, this worked for me to listen to changes in all documents in a collection using collectionGroup:
const unsub = () =>
onSnapshot(collectionGroup(db, "reservations"), (doc) => {
doc.docs.forEach((d) => {
console.log(d.data());
});
});

Array of JSON object is not empty but cannot iterate with foreach, show zero length [duplicate]

This question already has an answer here:
How to get data from firestore DB in outside of onSnapshot
(1 answer)
Closed 3 years ago.
I read a collection about book checkout from firestore in create().
The data is store in checkout array that declared in data().
export default {
name: "checkout-history",
data() {
return {
checkout: []
]
};
},
created() {
db.collection("checkout")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
id: doc.id, // firebase document id
book_did: doc.data().book_did,
borrowed_date: doc.data().borrowed_date,
copies_did: doc.data().copies_did,
due_date: doc.data().due_date
};
this.checkout.push(data); // push to array
});
});
console.log(this.checkout) // show data, as in the image below
console.log(this.checkout.length) // get 0
console.log(Object.keys(this.checkout).length) // get 0
}
......
When I run console.log(this.checkout);, console show this:
However, I cannot iterate it, the console show this.checkout.length is 0
I also tried to use Object.keys but no luck.
Object.keys(this.checkout).forEach(key => {
const keys = this.checkout[key];
console.log(keys);
});
I really don't know what to do anymore.
I read many answers online and tried most of them, but none of them work.
I guess you are executing your code before the completion of the request.
If you hover over the little blue i icon, it says:
Value below was evaluated just now.
Data is loaded from Firestore (and from most modern web APIs) asynchronously. This means that the rest of your code continues to execute after you start the query, and then when the data comes back from the database, your then() callback is called. This in turn means that all code that needs access to the data from the database, must be inside the then() callback.
db.collection("checkout")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
id: doc.id, // firebase document id
book_did: doc.data().book_did,
borrowed_date: doc.data().borrowed_date,
copies_did: doc.data().copies_did,
due_date: doc.data().due_date
};
this.checkout.push(data); // push to array
console.log(this.checkout) // show data, as in the image below
console.log(this.checkout.length) // get 0
console.log(Object.keys(this.checkout).length) // get 0
});
});
}
......
Also see:
How to get data from firestore DB in outside of onSnapshot
Why are Firebase APIs asynchronous?

Returning a record with a string in ember

I am trying to implement a search function where a user can return other users by passing a username through a component. I followed the ember guides and have the following code to do so in my routes file:
import Ember from 'ember';
export default Ember.Route.extend({
flashMessages: Ember.inject.service(),
actions: {
searchAccount (params) {
// let accounts = this.get('store').peekAll('account');
// let account = accounts.filterBy('user_name', params.userName);
// console.log(account);
this.get('store').peekAll('account')
.then((accounts) => {
return accounts.filterBy('user_name', params.userName);
})
.then((account) => {
console.log(account);
this.get('flashMessages')
.success('account retrieved');
})
.catch(() => {
this.get('flashMessages')
.danger('There was a problem. Please try again.');
});
}
}
});
This code, however, throws me the following error:
"You cannot pass '[object Object]' as id to the store's find method"
I think that this implementation of the .find method is no longer valid, and I need to go about returning the object in a different manner. How would I go about doing this?
You can't do .then for filterBy.
You can't do .then for peekAll. because both will not return the Promise.
Calling asynchronous code and inside the searchAccount and returning the result doesn't make much sense here. since searchAccount will return quickly before completion of async code.
this.get('store').findAll('account',{reload:true}).then((accounts) =>{
if(accounts.findBy('user_name', params.userName)){
// show exists message
} else {
//show does not exist message
}
});
the above code will contact the server, and get all the result and then do findBy for the filtering. so filtering is done in client side. instead of this you can do query,
this.store.query('account', { filter: { user_name: params.userName } }).then(accounts =>{
//you can check with length accounts.length>0
//or you accounts.get('firstObject').get('user_name') === params.userName
//show success message appropriately.
});
DS.Store#find is not a valid method in modern versions of Ember Data. If the users are already in the store, you can peek and filter them:
this.store.peekAll('account').filterBy('user_name', params.userName);
Otherwise, you'll need to use the same approach you used in your earlier question, and query them (assuming your backend supports filtering):
this.store.query('account', { filter: { user_name: params.userName } });

Categories