I am trying to fetch a value from my collection using the createdAt property, which is a timestamp.
This is roughly what my query looks like:
function getDataFromYesterdayToNow (db){
const now = new Date()
const yesterday = new Date(now.setDate(now.getDate() - 1))
yesterday.setHours(0, 0, 0, 0)
const { Timestamp } = firebase.firestore
return db
.collection('myData')
.where('createdAt', '>=', Timestamp.fromDate(yesterday))
.where('createdAt', '<=', Timestamp.fromDate(now))
.get()
}
However, when I run this, I get the following error:
error was 'FirebaseError: [code=invalid-argument]: Function Query.where() called with invalid data. Unsupported field value: a custom Timestamp object'. Stacktrace was 'FirebaseError: Function Query.where() called with invalid data. Unsupported field value: a custom Timestamp object
I am super confused, I have always fetched using Timestamp objects in other collections, and it does not work if I try to just use the date object. Have I forgotten something?
Edit: as requested, here is an example of what my doc looks like:
{
name: "My Data Name", // (string)
createdAt: November 9, 2018 at 8:40:45 PM // (Timestamp)
}
I had the same issue. There are two things you need to check.
1. Am I using the right SDK?
Did you know there are two different firebase SDK you can use? One is a client SDK (firebase-js-sdk a.k.a. firebase package) and the other one is a firebase server SDK (nodejs-firestore .a.k.a. #google-cloud/firebase package). These two libraries have its own implementation on firestore.Timestamp class and THEY ARE NOT COMPATIBLE.
Some of the other NPM packages dependencies as follow:
"#firebase/firestore" (*)
-> "firebase" (client SDK which imports all #firebase/* except #firebase/testing)
-> "#angular/fire" (and other client libraries with firebase binding)
-> "#firebase/testing" (mocking Firestore client)
"#google-cloud/firebase" (*) (server SDK)
-> "firebase-admin"
-> "firebase-functions-test"
Where (*) denotes the location of firestore.Timestamp definition.
In short, you should use corresponding Timestamp.
Case 1. Use a client SDK only
import { firestore, initializeApp } from 'firebase';
import { config } from './my-firebase-config';
const app = initializeApp(config);
app.firestore().collection('users')
.where('createdAt', '<=', firestore.Timestamp.fromDate(new Date()))
.get();
Case 2. Use a server SDK only
import { firestore, initializeApp } from 'firebase-admin';
const app = initializeApp();
app.firestore().collection('users')
.where('createdAt', '<=', firestore.Timestamp.fromDate(new Date()))
.get();
Case 3. Mixing SDKs
Sometimes you need to use client SDK (specifically, #firebase/testing) when you're testing code that are run on server (e.g. firebase functions.)
// server.ts
import { firestore, initializeApp } from 'firebase-admin';
const app = initializeApp();
app.firestore().collection('users')
.where('createdAt', '<=', fs.Timestamp.fromDate(new Date()))
.get();
// server.test.ts
import { firestore } from 'firebase';
import { initializeAdminApp } from '#firebase/testing';
// Replace server sdk with client sdk
jest.mock('firebase-admin', () => ({
firestore,
initializeApp: () => initializeAdminApp()
}));
2. Am I using the right version?
If you're using the correct SDK, the next thing to check is whether you're using the same version of Timestamp implementation. If you're using Client SDK for example, then you should check your package-lock.json whether it has a unique version of firebase.
For my case, I installed #firebase/testing and firebase in a different time, and due to the difference firebase version dependency from #firebase/testing, I had two different firebase packages installed at the same time. You can update an old package to fix this.
Related
I'm trying to create a new document when a user signs up for my app.
However, 'exports' is returning "Uncaught (in promise) ReferenceError: exports is not defined".
The code below is handling the function. I do also have an onAuthStateChanged function that switches some logged-in/out elements, although I don't think that could be stopping exports from being defined.
import { createUserWithEmailAndPassword, onAuthStateChanged,
signInWithEmailAndPassword } from "firebase/auth";
import { db, auth } from "./firebase";
import { collection, doc, setDoc, addDoc } from "firebase/firestore";
const signUpForm = document.querySelector('#signup-form');
if (signUpForm) {
signUpForm.addEventListener('submit', (e) => {
e.preventDefault();
//get user info
const email = signUpForm['signup-email'].value;
const password = signUpForm['signup-password'].value;
createUserWithEmailAndPassword(auth, email, password).then((cred) => {
const overlay = document.getElementById('overlay');
overlay.classList.add('hidden');
overlayP.classList.remove('hidden');
signUpForm.reset();
exports.createUserDoc = functions.auth.user().onCreate((user) => {
return admin.firestore().collection("users").doc(user.uid).setDoc({
email: user.email,
uid: user.uid,
})
});
// document.getElementById("signUpErr").innerHTML = "";
})
// .catch(err => {
// document.getElementById("signUpErr").innerHTML = err.message;
// });
});
};
I have initialized firebase and installed express.js within my index.js file but am I missing something to make sure this parameter is defined? I'm using Vite as a package bundler and node.js.
I'm new to coding and firebase, any advice would be massively appreciated.
I managed to solve this issue by taking a few days to read the documentation and understand what is going on with Cloud functions. The benefit of having a cloud function is that you can create triggers to your database that is away from your client-side code, improving security.
I was trying to call the cloud function within my app.js file and not within the firestore functions index.js file created when initializing firebase. Here you import through CommonJS Modules (CJS) the required SDK, in my case it was functions and admin.
Now my cloud functions live within index.js in /Functions folder separate from my app files.
// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
I also had to change the .setDoc() function to .set() as this was a Type error. I also added a userDelete function to delete users' documents in firestore.
exports.createUserDoc = functions.auth.user().onCreate(user => {
// Your new auth record will have the uid and email on it because
// you used email as the way to create the auth record
return admin.firestore().collection("users").doc(user.uid).set({
email: user.email,
bookmarked: []
})
});
exports.userDeleted = functions.auth.user().onDelete(user => {
const doc = admin.firestore().collection("users").doc(user.uid);
return doc.delete();
});
I would also like to note that setting up the firestore emulator has been very useful in this process and I'm sure will help me develop and test the other functions I need to create my app.
I used npm to install the Binance API node. I reach to the following step:
import Binance from 'binance-api-node'
const client = Binance()
// Authenticated client, can make signed calls
const client2 = Binance({
apiKey: 'xxx',
apiSecret: 'xxx',
getTime: xxx, // time generator function, optional, defaults to () => Date.now()
})
client.time().then(time => console.log(time))
Could you please guide me on how to run this part. The node module could be found on https://github.com/Ashlar/binance-api-node
You'll need to create your API key following this doc
2. Once you have your API key and secret key, you store in apiKey and apiSecret respectively.
3. If you do not have an appropriate babel config, you will need to use the basic commonjs requires.
const Binance = require('binance-api-node').default instead of ES6 import
I want to make a cloud function that uses 'firebase' module (not a 'firebase-functions')
And when I'm using or even only import it, npm throws an error:
Error: Error parsing triggers: Failed to load gRPC binary module because it was not installed for the current system
Expected directory: node-v64-darwin-x64-unknown
Found: [node-v79-darwin-x64-unknown]
This problem can often be fixed by running "npm rebuild" on the current system
Original error: Cannot find module '/Users/rame/functions/node_modules/grpc/src/node/extension_binary/node-v64-darwin-x64-unknown/grpc_node.node'
1) If you want to compile the package/file into executable, please pay attention to compilation warnings and specify a literal in 'require' call. 2) If you don't want to compile the package/file into executable and want to 'require' it from filesystem (likely plugin), specify an absolute path in 'require' call using process.cwd() or process.execPath
here's my code on Type script:
import * as functions from 'firebase-functions';
import admin = require('firebase-admin');
//the cause of an error
import * as firebase from 'firebase';
admin.initializeApp()
export const getProfilePicture = functions.https.onRequest((request, response) => {
//also there
const uid = firebase.auth().currentUser?.getIdToken
const promise = admin.storage().bucket().file('usersPfp/' + uid).getSignedUrl({
action: 'read',
expires: '03-09.2441'
})
const p2 = promise.then(GetSignedUrlResponse => {
const data = GetSignedUrlResponse[0]
return response.send({"data": data})
})
p2.catch(error =>{
console.log(error)
return response.status(500).send({"error": error})
})
})
How to fix that?
What you're doing isn't supported. The Firebase Authentication JavaScript client library isn't supported for use in backend environments like Cloud Functions.
The idea of a current user:
firebase.auth().currentUser
only makes sense in the client app where the user is signed in. It's not something that's known on the backend.
What you can do instead is send the user's ID token from your client to your function, the use the Admin SDK to verify it, then perform some actions on the user's behalf.
I have a Vue.js app. This app is a progressive web app, so it's intended to primarily run on the client-side. However, during the initial start-up, I need to authenticate the user in my Azure Active Directory, get data associated with their account, and store it for offline use.
I have a server-side API in place already for retrieving the data associated with a user account. I also know how to store it for offline use. However, my question is: how do I authenticate with the Microsoft Graph from my Vue.js app? Everything I see relies on using Node.js middleware, but unless I'm misunderstanding something, my progressive web app isn't a Node.js app. It's just straight up JavaScript, HTML, and CSS.
If the user closes the app, then revisits it in a couple of days, I believe I would need to use the refresh token to get a new access token. Still, once again, everything I see relies on Node.js middleware. I believe I need a solution that works purely in Vue.js / JavaScript. Am I mistaken?
Updates
1) Installed the Microsoft Graph Client via NPM (npm install #microsoft/microsoft-graph-client --save). This installed v1.7.0.
2) In my Vue.js app, I have:
import * as MicrosoftGraph from '#microsoft/microsoft-graph-client';
import * as Msal from 'msal';
let clientId = '<some guid>';
let scopes = ['user.read'];
let redirectUrl = 'http://localhost:1234/'; // This is registered in Azure AD.
let cb = (message, token, error, tokenType) => {
if (error) {
console.error(error);
} else {
console.log(token);
console.log(tokenType);
}
}
let reg = new Msal.UserAgentApplication(clientId, undefined, cb, { redirectUrl });
let authProvider = new MicrosoftGraph.MSALAuthenticationProvider(reg, scopes);
The last line generates an error that says: export 'MSALAuthenticationProvider' (imported as 'MicrosoftGraph') was not found in '#microsoft/microsoft-graph-client'
The last line generates an error that says: export 'MSALAuthenticationProvider' (imported as 'MicrosoftGraph') was not found in '#microsoft/microsoft-graph-client'
This error occurs because the main script (lib/src/index.js) of #microsoft/microsoft-graph-client does not export that symbol. You'll notice that logging MicrosoftGraph.MSALAuthenticationProvider yields undefined. Actually, the main script is intended to be run in Node middleware.
However, #microsoft/microsoft-graph-client provides browser scripts that do make MSALAuthenticationProvider available:
lib/graph-js-sdk-web.js
browserified bundle (not tree-shakable)
sets window.MicrosoftGraph, which contains MSALAuthenticationProvider
does not export any symbols itself
import '#microsoft/microsoft-graph-client/lib/graph-js-sdk-web'
let authProvider = new window.MicrosoftGraph.MSALAuthenticationProvider(/* ... */)
demo 1
lib/es/browser/index.js
ES Modules (tree-shakable)
exports MSALAuthenticationProvider
import { MSALAuthenticationProvider } from '#microsoft/microsoft-graph-client/lib/es/browser'
let authProvider = new MSALAuthenticationProvider(/* ... */)
demo 2
lib/src/browser/index.js
CommonJS module (not tree-shakable)
exports MSALAuthenticationProvider
import { MSALAuthenticationProvider } from '#microsoft/microsoft-graph-client/lib/src/browser'
let authProvider = new MSALAuthenticationProvider(/* ... */)
demo 3
Cloud Functions - Cloud Firestore error: can't get serverTimestamp
const admin = require('firebase-admin');
exports.userlog = functions.firestore
.document('user/{userId}')
.onUpdate((change, context) =>
{
const db = admin.firestore();
//var timestamp = db.FieldValue.serverTimestamp();
var timestamp = db.ServerValue.TIMESTAMP;
...
return db.collection('userlog').add(
{
userId : previousValue.userId,
...
timestamp: timestamp
}).then(ref =>
{
return console.log('Added document with ID: ', ref.id);
});
});
I got two errors separately:
TypeError: Cannot read property 'serverTimestamp' of undefined
TypeError: Cannot read property 'TIMESTAMP' of undefined
The correct syntax is:
firebase.firestore.FieldValue.serverTimestamp()
Note the lack of parenthesis (()) after firestore: this is a static variable, not an instance variable/member field.
// Imports: Dependencies
const admin = require('firebase-admin');
// Correct Syntax (If You Don't Want To Import Firestore)
created_at: admin.firestore.FieldValue.serverTimestamp(),
since #FrankvanPuffelen's edit queue is full with missing imports, documentation, etc I'll post an update on his solution
include from (web version 8):
const firebase = require('firebase-admin');
or use more recent (web version 9):
import {FieldValue} from "firebase/firestore";
The correct syntax is:
firebase.firestore.FieldValue.serverTimestamp()
Note the lack of parenthesis (()) after firestore: this is a static variable, not an instance variable/member field.
See Firebase example for more info
I was using the correct syntax as per the upvoted answer(s), but still go this error. It turns out it had something to do with my version of the firebase CLI being off-sync with versions of the firebase-admin package (I'm not sure how it happened in the first place, but I noticed form my source tracking tool that the package.json and lock files had been updated).
Solved the problem by deleting all changes I had made on my package.json & lock files and re-installed the CLI:
npm i -g firebase-tools