empty array when querying map of array in Firebase - javascript

I'm trying to get all messages in a chat. Each doc has a "messages" array, which maps to message body, createdAt, and sender's username. There is a second array for all users in chat.
How do I return all of the last 10 elements of the messages array?
Code:
exports.getChat = (req, res) => {
let chatData = {};
db.doc(`/chats/${req.params.chatId}`)
.get()
.then((doc) => {
if (!doc.exists) {
return res.status(404).json({ error: "Chat not found." });
}
chatData = doc.data();
chatData.chatId = doc.id;
return db
.collection("chats")
.where("chatId", "==", req.params.chatId)
.get();
})
.then((data) => {
chatData.messages = [];
data.forEach((doc) => {
chatData.messages.push(doc.data());
});
return res.json(chatData);
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
};
The code I have so far returns an empty messages array.

When querying Firestore, it's not possible to instruct the query to filter items out of an array field. You have to read the entire array field, then decide what you want to do with the items in that array. So, this means that a second query is not helpful here. You have everything you need in the first document snapshot.
db.doc(`/chats/${req.params.chatId}`)
.get()
.then((doc) => {
if (!doc.exists) {
return res.status(404).json({ error: "Chat not found." });
}
const chatData = doc.data();
// chatData now contains the entire contents of the document in the screenshot
const messages = chatData.messages
// messages now contains the entire array of messages - use however many want
})

Related

Cannot fetch list of UIDs inside "users" collection in firebase using reactjs

constructor(props) {
super(props);
this.state = {
users:[]
};
}
//method to get the data from users collection
async componentDidMount() {
const db = firebase.firestore();
db.collection("users")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.data());
console.log(data);
this.setState({ users: data });
})
.catch( err =>{
console.log(err);
});
}
this function returning an empty error
i want to print list of users uid
here i have users collection and inside it i have retailers collection and its document
One thing you have to realize here is that your users collection contains no documents. The document IDs are shown in italics, which means that there is no document here. The IDs are visible because there is a nested subcollection under each document. They are shown like this in the console so that you can click through and navigate to the nested subcollection, despite the document being missing.
If you want to list users with a query, you will have to actually create documents in the users collection. They can be empty if you don't have any information. But you do need actual documents in the users collection in order for anything to show up in a query.
This line in your current code querySnapshot.docs.map(doc => doc.data()) takes the data of each document. But you're keeping the UID in the ID of each document, so you'll want to use:
const db = firebase.firestore();
db.collection("users")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.id);
console.log(data);
this.setState({ users: data });
})
.catch( err =>{
console.log(err);
});
Update: As Doug pointed out in his answer, if there are no actual user documents, your get() call will not return it.
I highly recommend creating user documents, even if it's just an empty one.
For now, the only way to get the UID would be to load all retailers for all users, and then use those results to get the ID of the parent documents:
const db = firebase.firestore();
db.collectiongroup("retailers")
.get()
.then(querySnapshot => {
querySnapshot.forEach((doc) => {
console.log("retailed "+doc.id+" for user "+doc.ref.parent.parent.id);
});
})
.catch( err =>{
console.log(err);
});
You'll have to deduplicate the UIDs, but that will leads to getting the UIDs.
But you'll be loading all retailers for all users this way, so as said, I highly recommend storing a small/empty user document instead.
The data method on querySnapshot.docs gets the data now to get the id of each document you need to add access the id property as UID is stored in id property
async componentDidMount() {
const db = firebase.firestore();
db.collection("users")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.data().id);
console.log(data);
this.setState({ users: data });
})
.catch( err =>{
console.log(err);
});
}

Storing Tags in Firebase from a POST request for a different collection in Node.js

I have two collections, posts and tags. posts contains a postId and other metadata, including tags. This is what a post would look like:
{
"tags": [
"tag1",
"tag2",
...
],
"message": "test message"
...
}
This returns the post above, with a postId.
Using Axios, I receive this data in my function. I want to take each tag, put them in the tags collection along with the postId associated with it.
An example of the tags collection:
tags: {
tag1: {
"postId1",
"postId2"
},
tag2: {
"postId1",
"postId3"
}
}
I'm stuck adding the tags to its own collection in Firebase, and I've tried using forEach tag and updating the tags collection one by one, but that hasn't been working for me.
The code I currently have:
db.collection("posts")
.add(oneNewPost)
.then((doc) => {
// add the post body to the "posts" collection
const resPost = oneNewPost;
resPost.postId = doc.id;
res.json(resPost);
})
.then(() => {
// DOESNT WORK HERE --> overwrites changes in firebase "tags" collection
let batch = db.batch();
resPost.tags.forEach((doc) => {
const docRef = db.collection("tags").doc(doc);
batch.update(docRef, { postId: resPost.postId }, { merge: true });
});
batch.commit().then(() => {
return res.json({...resPost});
});
})
.catch((err) => {
res.status(500).json({ error: "something went wrong" });
console.error(err);
});
Please let me know if anything is unclear!
I got it to work using the following code:
.then((resPost) => {
// add postId's to tag collection here
let batch = db.batch();
resPost.tags.forEach((doc) => {
const docRef = db.doc(`/tags/${doc}`);
batch.update(
docRef,
{ postId: admin.firestore.FieldValue.arrayUnion(resPost.postId) },
{ merge: true }
);
});
batch
.commit()
.then(() => {
return res.json({ ...resPost });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
})
Basically, you need to do a batch update, but also for a specific FieldlValue for each postId.

How to get a result of a Parse Server Query

How can I get the values of the searched objects?
const query = new Parse.Query(Parse.User);
query.equalTo("sexo", "feminino");
query
.find()
.then(results => {
console.log(results.get("username"));
})
.catch(error => {
console.log(error);
});
TypeError: "results.get is not a function"
How to get values of a search query in Parse server ?
Query.find will be able to fetch the results of your queries.
As you can have multiples results, the object that you get is an array of elements
so if you want to display the name of all users of your query you'll have to iterate to display all of your users.
const query = new Parse.Query(Parse.User);
query.equalTo("sexo", "feminino");
query
.find()
.then(results => {
results.forEach(user => {
console.log(user.get("username"))
});
})
.catch(error => {
console.log(error);
});
If you want to have examples of queries click here
Hope my answer help you 😊

Get Cloud Firestore database collection

I'm trying to get data from my database hierarchy db.collection/doc/collection/
I need to get the data from the collection "product"
I can already filter out the right document, by using this snippet.
Still, didn't manage to get any data from the next collection.
db.collection('deliveryservice').where('owner_id', '==', user.uid).collection('product').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
Please try the following way to retrieve data from your product collection.
var docRef = db.collection("deliveryservice").doc(user.uid).collection('product');
docRef.get().then((snapshot) => {
snapshot.docs.forEach(doc => {
}
}).catch(function(error) {
console.log("Error getting document:", error);
})

Perform a simple select query in Firebase Firestore

How can I perform a simple search in Firebase Firestore to check if a record exists in a collection? I've seen this code in the documentation, but it is not complete.
// Create a reference to the cities collection
var citiesRef = db.collection('cities');
// Create a query against the collection
var queryRef = citiesRef.where('state', '==', 'CA');
In my use case I want to check the rejected contacts collection for a given number. This is my code
const collectionRef = db.collection('rejectedContacts');
const queryRef = collectionRef.where('contact','==',phone);
let contactRejected: boolean = queryRef.get.length>0 ;
if (contactRejected) {
return response.json(
{
status: 0,
message: `Contact , ${phone} is blocked. Please try again with another one.`,
result: null
});
}
I've checked the function with a rejected number, which i added manually in the collection, but it is not responding with the rejected message. How can I get the count or the row itself with a select query. What is wrong with my code?
UPDATE 1
As #Matt R suggested, I updated the code with this
let docRef = db.collection('rejectedContacts').where('contact', '==', phone).get();
docRef.then(doc => {
if (!doc.empty) {
return response.json(
{
status: 0,
message: `Contact , ${phone} is blocked. Please try again with another one.`,
result: null
});
} else {
return response.json(
{
status: 0,
message: `Contact , ${phone} is not blocked`,
result: null
});
}
})
.catch(err => {
console.log('Error getting document', err);
});
But when checked with the existing number, it is returning with not blocked
Edit 2
return collectionRef.select('contact').where('contact', '==', phone).get()
.then(snapShot => {
let x : string = '['
snapShot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
x+= `{${doc.data}},`;
});
return response.send(x);
});
It is only returning the value of x from this line
let x : string = '['
Firestore's get() method returns a promise and response, I would try in this format to handle whether the document exists or not. This format may also lend better error messages when troubleshooting.
EDIT / UPDATED: Using the where clause returns a snapshot that must be iterated through, because it can return multiple documents. See documentation here: https://firebase.google.com/docs/firestore/query-data/get-data#get_multiple_documents_from_a_collection
Updated code with your example.
var collectionRef = db.collection('rejectedContacts');
var query = collectionRef.where('contact','==',phone).get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
})
.catch(err => {
console.log('Error getting documents', err);
});

Categories