Firestore pagination backwards goes to first record always - javascript

I am making a simple Firestore pagination.
When it goes forward works as expected, but when it should go backwards it always goes to the first record.
I have been stuck here for a while, even crammed both (forward and backward) in the same function to ease the debugging.
Edit:
Added simplified version (still the same undesired results):
async init() {
const result = await (await firestore())
.collection('documents')
.limit(this.limit)
.orderBy('createTimestamp')
// .orderBy('userName')
.get()
console.log(result)
this.lastVisible = result.docs[result.docs.length - 1]
;[this.firstVisible] = result.docs
result.forEach(doc => {
console.log('doc', doc.data())
this.myDocuments.push(doc)
})
},
async forward() {
const result = await (await firestore())
.collection('documents')
.orderBy('createTimestamp')
// .orderBy('userName')
.startAfter(this.lastVisible)
.limit(this.limit)
.get()
this.lastVisible = result.docs[result.docs.length - 1]
;[this.firstVisible] = result.docs
if (result.empty === false)
result.forEach(doc => {
console.log('doc', doc.data())
this.myDocuments.push(doc)
})
},
async backward() {
const result = await (await firestore())
.collection('documents')
.orderBy('createTimestamp')
// .orderBy('userName')
.endBefore(this.lastVisible)
.limit(this.limit)
.get()
this.lastVisible = result.docs[result.docs.length - 1]
;[this.firstVisible] = result.docs
if (result.empty === false)
result.forEach(doc => {
console.log('doc', doc.data())
this.myDocuments.push(doc)
})
},
Added the calling method:
getAllDocuments: async ({ rootState, commit }, payload) => {
const documentsDb = new DocumentsDB(`${rootState.authentication.user.id}`)
console.log('Get all documents(admin)')
console.log('payload :>> ', payload)
const { startAt, endBefore, constraints, limit } = payload
console.log('startAt :>> ', startAt)
console.log('endBefore :>> ', endBefore)
console.log('limit :>> ', limit)
const documents = await documentsDb.readWithPagination(constraints, startAt, endBefore, limit)
console.log('documents', documents)
// const documents = await documentsDb.readAllAsAdmin()
// console.log('documents: ', documents)
commit('setDocuments', documents) },
I left the console.log() for debuging reasons.
payload :>> {constraints: null, endBefore: "2UxB7Z1HWCmvkEcfLZ5H", startAt: null, limit: 5}constraints: nullendBefore: "2UxB7Z1HWCmvkEcfLZ5H"limit: 5startAt: null__proto__: Object
Thhe original code
async readWithPagination(constraints = null, startAt = null, endBefore = null, limit = null) {
const collectionRef = (await firestore()).collection(this.collectionPath)
let query = collectionRef
if (limit) query = query.limit(limit)
query.orderBy('createTimestamp')
if (constraints) {
constraints.forEach(constraint => {
query = query.where(...constraint)
})
}
query = query.orderBy(firebase.firestore.FieldPath.documentId())
if (startAt) {
query = query.startAfter(startAt)
}
if (endBefore) {
query = query.endBefore(endBefore)
console.log('query :>> ', query)
}
const formatResult = result =>
result.docs.map(ref =>
this.convertObjectTimestampPropertiesToDate({
id: ref.id,
...ref.data(),
})
)
return query.get().then(formatResult) }
Edit as requested in comments:
dispatchPaginatedForwardDocuments(startAt = null) {
const payload = {}
payload.orderBy = [['createTimestamp', 'asc']]
payload.constraints = [['status', '==', 4]]
payload.limit = this.limit
payload.startAt = startAt?.id || null
this.$store.dispatch('admin/getPaginatedForwardDocuments', payload, { root: true })
},
dispatchPaginatedPrevDocuments() {
const payload = {}
payload.orderBy = [['createTimestamp', 'asc']]
payload.constraints = [['status', '==', 4]]
payload.limit = this.limit
payload.startAt = this.lastDocument.id
payload.endBefore = this.firstDocument.id
this.$store.dispatch('admin/getPaginatedBackwardsDocuments', payload, { root: true })
},
And this:
import UserDocumentsDB from '#/firebase/user-documents-db'
// import UsersDB from '#/firebase/users-db'
import DocumentsDB from '#/firebase/documents-db'
import { storage } from 'firebase'
export default {
// Fetch documents with pagination forwards and constraints
// This works as expected
getPaginatedForwardDocuments: async ({ rootState, commit }, payload) => {
const documentsDb = new DocumentsDB(`${rootState.authentication.user.id}`)
const documents = await documentsDb.readPaginatedForward(payload)
console.log('documents: ', documents)
commit('setDocuments', documents)
},
// Fetch documents with pagination backwards and constraints
getPaginatedBackwardsDocuments: async ({ rootState, commit }, payload) => {
console.log('getPaginatedBackwardsDocuments', payload)
const documentsDb = new DocumentsDB(`${rootState.authentication.user.id}`)
const documents = await documentsDb.readPaginatedBackwards(payload)
console.log('documents: ', documents)
commit('setDocuments', documents)
},

Related

http://localhost:9000/api/users net::ERR_CONNECTION_REFUSED and jwt must be provided

I am creating a blog application. In every parameterized route I get the details of that specific user.For eg: /profile/#randomuser get the details of #randomusers, /profile/#robert get the details of #robert. I get the details of parameterized toute users but not the user who log in to the blog application.
Everything is imported correctly.
<Route path="/profile/:profile" element={\<Profile /\>}
Profile.jsx
const [user, getUser] = useState([])
const [glbUser, setUser] = useContext(UserContext)
const match = useParams().profile
const match = useMatch('/profile/:profile')
const userMatch = match.params.profile
console.log(" usematchis ", userMatch)
const userParams = useParams().profile
useEffect(() => {
async function fetchGlbUser() {
const loggedInUser = window.localStorage.getItem('userToken')
if (loggedInUser) {
const user = JSON.parse(loggedInUser)
loginServices.setToken(user.token)
// loginServices.createToken()
const config = { headers: { Authorization: user.token } }
const glbUser = await axios.get("${postUrl}", config)
setUser(glbUser.data.glbUserToken)
return glbUser.data.glbUserToken
}
}
fetchGlbUser()
}, [])
// console.log("Match is", match)
// console.log("Type of Match is", typeof match.params.profile)
useEffect(() =\> {
axios.get("http://localhost:9000/api/users/${userMatch}", { params: { profile: userMatch } })
.then(res =\> {
console.log(res.data)
getUser(res.data)
// getUser(res.data.newUser)
})
.catch(err => console.log(err))
// const getUserData = async () => {
// const res = loginServices.getProfile(`http://localhost:9000/api/users/${userMatch}`, {params:{profile:userMatch}})
// return res.data
// }
// getUserData()
}, [])
Backend.js
router.get('/:profile', async (req, res) =\> {
console.log(req)
const username = req.params.profile
const decodedToken = jwt.verify(getToken(req), process.env.SECRET_KEY)
// console.log(username)
// console.log(typeof username)
try {
const newUser = await User.findOne({ username })
const glbUserToken = await User.findById(decodedToken.id)
// console.log(newUser)
res.status(200).json({ newUser, glbUserToken })
} catch (err) {
console.log(err)
}
})
const getToken = req =>
const auth = req.get('authorization')
if (auth && auth.startsWith(`bearer `))
return auth.replace('bearer ', '') }
return null
}

When I log Array there's an object inside, but when I'm trying to access that object it returns me undefined

This is my cache "component":
// imports
const useCache = (cacheName: string, url: string) => {
const cacheArray: Array<Object> = []
const getAllCaches = async () => {
const cacheNames = await caches.keys();
for (const cname of cacheNames) {
const cacheStorage = await caches.open(cname);
const cachedResponse = await cacheStorage.match(url);
const cdata = await cachedResponse?.json()
cacheArray.push({name: cname, data: cdata})
}
}
useEffect(() => {
getAllCaches()
.catch(err => console.log(err))
}, [])
const addCache = (response: any) => {
const data = new Response(JSON.stringify(response));
if ('caches' in window) {
caches.open(cacheName).then((cache) => {
cache.put(url, data);
});
}
const finalData = {name: cacheName, data: response}
cacheArray.push(finalData)
return data
}
const getCache = (cacheName?: string) => {
if (cacheName) {
return cacheArray.filter((i: any) => i.name === cacheName)[0]
}
else {
return cacheArray
}
}
const removeCache = (cacheName: string) => {
caches.delete(cacheName).then(function (res) {
return res;
});
}
return [
getCache as (cacheName?: any) => any,
addCache as (response: any) => any,
removeCache as (cacheName: any) => any
]
};
export default useCache;
Now here's code in my home component:
const [getCache, addCache, removeCache] = useCache("user", "http://localhost:3000")
useEffect(() => {
console.log(getCache())
console.log(getCache()[0])
console.log(getCache().length)
// the rest of code, not matter
and when I run home component (with vite and preact) it logging me Array, then unfedinfed, then 0 (but second should return object, and third should return 1) also I attached a screen from console.
Why it's returning me undefined and 0 length when it should return object and 1?
I'm using preact, vite, newest nodejs, typescript

Firestore : why using serverTimestamp gives different results?

I am having a hard time understanding serverTimestamp in firestore.
When I save a document in database in a firebase function using Fieldvalue.serverTimestamp() or in a javascript client code using serverTimestamp() it sometimes doesn't save the same thing in the database.
See screenshots below :
Sometime I get an object with {nanoseconds: xxx, seconds: xxx} and sometimes I get a timestamp formatted date...
The problem is when I try to query my orders using query(collectionRefOrders, orderBy('createdAt', 'desc'), limit(10)).
The orders with the object appears before the others ones even if they are created after...
Any clue why this happens ? What am I doing wrong ?
Thanks a lot.
EDIT :
Here is the code I use to add documents in the my firebase function (it is a request function I call in a website) :
const { getFirestore, FieldValue } = require('firebase-admin/firestore');
const firebaseDB = getFirestore();
exports.createOrderFromTunnel = functions.region('europe-west3')
.runWith({
timeoutSeconds: 10,
memory: "4GB",
})
.https
.onRequest(async (req, res) => {
cors(req, res, async () => {
try {
const { apiKey } = req.body;
const project = await getProjectFromApiKey(apiKey);
if (!project) {
return res.json({
success: false,
error: 'Unauthorized: invalid or missing api key'
});
}
const contactData = {
address: {},
createdAt: FieldValue.serverTimestamp()
};
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: FieldValue.serverTimestamp(),
status: 'NEW',
};
const refProject = firebaseDB
.collection('projects')
.doc(project.id);
const colOrder = firebaseDB.collection(`projects/${project.id}/orders`)
const refOrder = colOrder.doc();
const colContact = firebaseDB.collection(`projects/${project.id}/contacts`)
const refContact = colContact.doc();
await firebaseDB.runTransaction(async transaction => {
const snapProject = await transaction.get(refProject);
const dataProject = snapProject.data();
const sequenceContact = dataProject.sequenceContact;
const sequenceOrder = dataProject.sequenceOrder;
contactData.sequence = sequenceContact;
orderData.sequenceNumber = sequenceOrder;
await transaction.set(refContact, contactData);
orderData.customer.id = refContact.id;
orderData.customer.sequence = sequenceContact;
await transaction.set(refOrder, orderData);
await transaction.update(refProject, {
sequenceContact: sequenceContact + 1,
sequenceOrder: sequenceOrder + 1,
totalContacts: dataProject.totalContacts + 1,
totalOrders: dataProject.totalOrders + 1,
});
return refOrder.id;
});
return res.json({
success: true
});
} catch (err) {
functions.logger.error(err);
return res.json({
success: false,
err
});
}
});
});
Here is the code I use to add documents in my client code (it is a web app in javascript) :
const createOrder = async (projectId) => {
try {
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: serverTimestamp(),
status: 'NEW',
surface: 0,
};
const refProject = doc(firebaseDB, 'projects', projectId);
const colOrder = collection(firebaseDB, `projects/${projectId}/orders`)
const refOrder = doc(colOrder);
return await runTransaction(firebaseDB, async (transaction) => {
const snapProject = await transaction.get(refProject);
if (!snapProject.exists()) {
throw "Document does not exist!";
}
const dataProject = snapProject.data();
const sequence = dataProject.sequenceOrder;
orderData.sequenceNumber = sequence;
transaction.set(refOrder, orderData);
transaction.update(refProject, { sequenceOrder: sequence + 1, totalOrders: dataProject.totalOrders + 1 });
return refOrder.id;
});
} catch (e) {
console.error(e);
return null;
}
};

Trouble understanding Cloud Function Error

I am new to cloud funcations node.js and type script. I am running the below code and getting the error below and can't make sense of it after watch a ton of videos about promises and searching other questions.
any help would be appreciated.
Function returned undefined, expected Promise or value
exports.compReqUpdated = functions.firestore
.document('/compRequests/{id}')
.onUpdate((change, contex)=>{
const newData = change.after.data();
//const oldData = change.before.data();
const dbConst = admin.firestore();
const reqStatus:string = newData.requestStatus;
const compId:string = newData.compID;
const reqActive:boolean = newData.requestActive;
if (reqStatus == "CANCELED" && reqActive){
const query = dbConst.collection('compRequests').where('compID', '==', compId);
const batch = dbConst.batch();
query.get().then(querySnapshot => {
const docs = querySnapshot.docs;
for (const doc of docs) {
console.log(`Document found at path: ${doc.ref.path}`);
console.log(doc.id);
const docRef = dbConst.collection('compID').doc(doc.id);
batch.update(docRef, {requestStatus: 'CANCELED',requestActive: false});
};
return batch.commit()
})
.catch(result => {console.log(result)});
}else{
return
}
});
The firebase docs state that the callback passed to the onUpdate function should return PromiseLike or any value, but you aren't returning anything right now. If you change your code to something as follows I reckon it should work as expected:
exports.compReqUpdated = functions.firestore
.document('/compRequests/{id}')
.onUpdate((change, contex) => {
const newData = change.after.data();
//const oldData = change.before.data();
const dbConst = admin.firestore();
const reqStatus: string = newData.requestStatus;
const compId: string = newData.compID;
const reqActive: boolean = newData.requestActive;
if (reqStatus == "CANCELED" && reqActive) {
const query = dbConst.collection('compRequests').where('compID', '==', compId);
const batch = dbConst.batch();
return query.get().then(querySnapshot => {
const docs = querySnapshot.docs;
for (const doc of docs) {
console.log(`Document found at path: ${doc.ref.path}`);
console.log(doc.id);
const docRef = dbConst.collection('compID').doc(doc.id);
batch.update(docRef, { requestStatus: 'CANCELED', requestActive: false });
};
return batch.commit()
}).catch(result => { console.log(result) });
} else {
return false;
}
});

Cosmos DB query with JavaScript API v2 query for 1 doc

I have an async call chain that looks like this:
getConnections()
.then(() => addOneNewDoc())
.then(() => fetchOneDoc());
The addNewDoc() works fine and inserts a document. I then use the query capabilities of the API to query for the document in fetchOneDoc().
The call to fetch doc always returns undefined, but I can go see the document in the portal db browser. I've tried sleeping between the calls in case the doc just didn't make it in before the query, but that didn't work either.
const query = `select * from items i where i.id = '${docId}'`;
const {result: doc} = await connection.container.items.query(query);
if (!doc) {
console.log('GOT NO DOCS BACK');
return;
}
I have validated the query works fine in the portal.
Please refer to my sample code:
const cosmos = require('#azure/cosmos');
const CosmosClient = cosmos.CosmosClient;
const endpoint = "https://***.documents.azure.com:443/"; // Add your endpoint
const masterKey = "***"; // Add the masterkey of the endpoint
const client = new CosmosClient({ endpoint, auth: { masterKey } });
const databaseId = "db";
const containerId = "coll";
async function run() {
await insertItem();
}
async function insertItem(continuationToken) {
const { container, database } = await init();
const documentDefinition = { content: 'Hello World!' };
const { body } = await container.items.create(documentDefinition);
console.log('Created item with content: ', body.id);
return await queryItems1(body.id);
}
async function queryItems1(idParam) {
const { container, database } = await init();
const querySpec = {
query: "SELECT r.id,r._ts FROM root r where r.id = '"+ idParam +"'"
};
const queryIterator = await container.items.query(querySpec,null);
if (queryIterator.hasMoreResults()) {
const { result: results, headers } = await queryIterator.executeNext();
console.log(results)
}
}
async function init() {
const { database } = await client.databases.createIfNotExists({ id: databaseId });
const { container } = await database.containers.createIfNotExists({ id: containerId });
return { database, container };
}
run().catch(err => {
console.error(err);
});

Categories

Resources