How to get two queries from firestore? - javascript

I use redux and want to know how to take and process two queries from firesotre.
export function getBlackList(data) {
return (dispatch, getState) => {
let db = loadFB().firestore();
let query = db.collection('users').where("report.total_point",">",0).orderBy("report.total_point","asc");
return query.get().then(docs=>{
let result = [];
console.log(result);
docs.forEach(doc=>{
let user = doc.data();
user.id = doc.id;
result.push(user);
})
dispatch({
type: types.SET_USER_LIST,
data: result,
page : 1
})
})
}
}
Through the code presented above, the component is processed through dispatch.
I get a query But I want to know how to get the two query values ​​together and sort them.
db.collection('users').where("memo",">","0").orderBy("memo","asc");
Is there a way to solve it using "promise all"?
Look forward to a good solution.

You can't use Promise.all to query two values from a same collection, Promise.all is used to retrieve data from a collection group [different collections] instead of from a single collection.
In order to query two values together, use the code below:
let query: db.collection('users').where("memo",">","0").where("memo2","<","3");
And after you can sort them:
query.orderBy("memo","asc");

Your query will return multiple items. Get them together you can use map and sort if you need.
Then the call to dispatch for redux looks ok to me.
query.get().then(docs => {
const users = docs.map(doc => ({
id: doc.id,
...doc.data(),
}));
// .sort(...)
dispatch({
type: types.SET_USER_LIST,
data: users,
page: 1,
});
});

Related

Query while iterating on array

I have Announcements and AnnouncementLikes schema. There is one schema for announcements and other one is for if user liked the specific announcement. My plan is sending announcements with like state to the user that made a request.
So on the below I tried to get like while iterating on announcement list.
const announcements = await AnnouncementModel.paginate(
{},
{
page,
limit,
lean: true
}
)
announcements.docs = announcements.docs.map((annonucement) => ({
...annonucement,
like: (async () => {
const result = await AnnouncementModel.findIfUserLiked(
annonucement.id,
req.userId
)
return result
})()
}))
It is inside of AnnouncementSchema I didnt want to copy all of the schema
static async findIfUserLiked(announcementId: string, userId: string) {
const foundAnnouncementLike = await AnnonucementLikeModel.findOne({
announcementId,
userId
})
return !!foundAnnouncementLike
}
I know that I cant get likes from immediatly invoked function because it returns a promise. So I have to stop iterate somehow and get like before sending to user. So i tried this solution but it didnt work as well
const fullOfPromises = announcements.docs.map((announcement) => announcement.like)
Promise.all(fullOfPromises).then(() => {
res.send(announcements)
})
I am new to mongoose and I dont know how to get user likes in the announcement list.
Thanks in advance

Trouble accessing firebase query results in document template

new to vue and firebase but stuck on this for hours. I have a vue3 app running a specific firebase9 query that will only return a maximum of 1 row (i.e. includes limit 1). The results are being returned but I am having trouble accessing the data so I can pass up to the template. I am using an example from a tutorial that was designed to return multiple rows from FB then iterate through in the template using v-for but in this case it will only ever be one row. All the tutorials I can find are similar not addressing how to deal with one row (or document) being returned. Oddly, the data is being returned to _rawValue but I can't seem to get to it...
Here's the JS snippet:
let collectionRef = collection(db, c)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
})
// update values
documents.value = results
})
return { documents }
Here's the Vue snippet:
const { documents: lastEvent } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
console.log('lastevent: ', lastEvent)
I can see that lastEvent does indeed contain an array with the values I am looking for so the query is running and returning, BUT, it is listed in something called "_rawValue" that I can't seem to access. For example I would like to set a variable to one of the values being returned like let myVar = lastEvent.id or lastEvent.created, etc.
[edit: use case is that I want to query the users last input so I that can set some of the form data default values based on their last entry]
Any help or reference to get me unstuck would be greatly appreciated.
Screenshot of console.log
Came up with a solution. Probably hacky but works.
First modify the getCollectionRt.js that runs the query as
...
const document = ref(null)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
document.value = { ...doc.data(), id: doc.id }
})
// update values
documents.value = results
})
return { documents, document }
then pull in 'document' and return in vue as:
const { documents: lastEvent, document } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
...
return {..., document }
then I can access it in the template as {{ document.id}}
Although this works, definitely spend more time learning about workign with object/arrays in VueJS

How to fetch all the documents with unique id from firestore database using React?

[Firestore SS][1]
[1]: https://i.stack.imgur.com/EI1Dm.png
I want to fetch each document as displayed in SS it's stored as Pets + unique_userId.
I am unable to fetch all data together. Just able to fetch one data of a particular user using the code below.
const [info,setInfo]=useState([]);
useEffect(() => {
db.collection("pets ESYXOPqlJpZ48np8LfNivnh9pvc2").onSnapshot((snapshot) =>
setInfo(snapshot.docs.map((doc) => doc.data()))
);
},[]);
Here ESYXOPqlJpZ48np8LfNivnh9pvc2 this is the userID of each unique user
Please help me out to fetch all the Pets data instead of hardcoding and fetching one particular data.
Try the following code,
const [docs, setDocs] = useState([]);
useEffect(() => {
const querySnapshot = await getDocs(collection(db,"pets ESYXOPqlJpZ48np8LfNivnh9pvc2"));
const document =[];
querySnapshot.forEach((doc) => {
document.push({
...doc.data(),
id: doc.id
});
});
setdocs(document);
}, []);
I'm guessing the appended id is a reference to the owner's id? In this case, would it be an option to fetch the owner list and use everyone's id to build a list of collection ids and then get all of their data?
If not, I only see to options:
Rethink your database structure - maybe use a unified pets collection and have a reference with/to that id in the pet documents.
Create a cloud function in which use #google-cloud/firestore to get the list of collections. There are tons of resources out there to help you get started with firebase cloud functions. Their documentation is pretty good also, and probably the most up-to-date
const functions = require('firebase-functions')
const { Firestore } = require('#google-cloud/firestore');
module.exports = functions
.region('europe-west3') // use the region you want here
.https.onRequest(async (request, response) => {
try {
const firestore = new Firestore();
const collections = (await firestore.listCollections()).map(collection => collection.id)
response.json({ data: collections })
} catch (error) {
response.status(500).send(error.message)
}
})
You'll get and endpoint which you can use to fetch the collection ids (e.g.: https://your-project-name.cloudfunctions.net/collections)
const [pets, setPets] = useState([]);
const [collectionIds, setCollectionIds] = useState([])
useEffect(() => {
fetch('https://your-project-name.cloudfunctions.net/collections')
.then(response => response.json())
.then(({ data }) => setCollectionIds(data))
}, [])
useEffect(() => {
collectionIds.forEach((collectionId) => {
// There are better ways to do this,
// I'm just using your approach so you can focus on the rest of the code
db.collection(collectionId).onSnapshot((snapshot) => {
setPets((currentPets) => [...currentPets, ...snapshot.docs.map((doc) => doc.data())])
})
})
}, [collectionIds])
Please note that these are very high-level implementations, there's no error handling, no teardowns or anything, so keep that in mind. Hope it helps, good luck!

How to retain the order of items (from server) for a key-index object after normalizing?

I am working on a react asp.net application. From the server, I return a list of items, ordered by date. Then, I normalize it using normalizr:
axios.get(url, { params: { userId, submissionId } })
.then(response => {
const notifications = new schema.Entity('notifications');
const normalizedData = normalize(response.data, [notifications]);
dispatch(
fetchNotificationsSuccess(normalizedData.entities.notifications)
);
})
.catch(error => { notificationDataOperationFailure(error) });
When I run this, the items are reordered by their key values starting from 1. I wonder how I can retain the order sent from the server.
You can find the order in the "result" you get, see more info here: https://github.com/paularmstrong/normalizr/issues/9

[TypeError]: Firebase orderByChild not working

I'm trying to query my database such that it retrieves an ordered list based on each child key. I do it as follows (see below), but "TypeError" happens. That is ordered at random when using .on('value', snapshot =>. I can't fix that, do you guys have any ideas to realize?
The Error
TypeError: In this environment the sources for assign MUST be an object. This error is a performance optimization and not spec compliant.
Realtime Database Query
Source Code
export const messagesFetch = (room) => {
return (dispatch) => {
firebase.database().ref(`/rooms/${room.roomId}/messages`)
.once('child_added', snapshot => {
dispatch({ type: 'messages_fetch_success', payload: snapshot.val() });
})
};
};
child_added will create a new snapshot for each message, instead of returning a list of messages in one object.
You might want to look at .once('value') instead of once('child_added').
As you wanted an ordered list I added the query orderByKey() which will return the messages in key order.
export const messagesFetch = (room) => {
return (dispatch) => {
firebase.database().ref(`/rooms/${room.roomId}/messages`)
.orderByKey()
.once('value')
.then(snapshots => {
snapshots.forEach(snapshot => {
dispatch({ type: 'messages_fetch_success', payload: snapshot.val() });
return false;
});
});
};
};
Is a react-native app, right?! If yes add a flag in question.
In firebase 'child_added' fires for each child and ever a new child has add, like sketchthat says. With 'once' you not listen the node, but, because 'child_added' you fires your function for every child. In other words your function return differents values (snapshot) for a same constant.

Categories