Detected an object of type "Timestamp" that doesn't match the expected instance
Asked Answered
M

3

12

I'm wondering why is the Timestamp object is not working as I expect?

It works in test environment (I use Mocha), but throws error when it has been deployed.

index.ts

import { Timestamp, QuerySnapshot } from "@google-cloud/firestore";
....

async someFunction() {
   let col = firestore.collection("mycollection");
   let now = Timestamp.now();
   let twentyMinsAgo = Timestamp.fromMillis(now.toMillis() - (1200 * 1000));

   return col
      .where('LastEdited', '>=', twentyMinsAgo) //This throws error
      .get()
}

Stack Trace

Argument "value" is not a valid QueryValue. 
Detected an object of type "Timestamp" that doesn't match the expected instance. 
Please ensure that the Firestore types you are using are from the same NPM package.
      at Validator.(anonymous function).err [as isQueryValue] (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/validate.js:99:27)
      at CollectionReference.where (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/reference.js:940:25)

package.json

"dependencies": {
   ....
   "@google-cloud/firestore": "^0.16.0",
   "firebase-admin": "~6.0.0",
   "firebase-functions": "^2.0.5"
}
Moonlight answered 2/10, 2018 at 13:4 Comment(0)
M
14

Now I get it why it throws an error. Because I import Firestore object separately, whereas I should just use Firestore object from Firebase Admin SDK.

What I changed:

  1. remove "@google-cloud/firestore" dependency from package.json

  2. Use admin.firestore.Timestamp object.

index.ts

async someFunction() {
   let col = firestore.collection("mycollection");
   let now = admin.firestore.Timestamp.now();
   let twentyMinsAgo = admin.firestore.Timestamp.fromMillis(now.toMillis() - (1200 * 1000));

   col.where('LastEdited', '>=', twentyMinsAgo) //Now ok
      .get()
}
Moonlight answered 2/10, 2018 at 13:34 Comment(0)
A
4

when using firebase admin avoid importing and using any of the client side package directly

so instead of

 import * as admin  from "firebase-admin";
 import firebase from "firebase/app";

 admin.firestore().collection("name").set({
       date: firebase.firestore.Timestamp.now()
})

use this instead

 import * as admin  from "firebase-admin";

 admin.firestore().collection("name").set({
       date: admin.firestore.Timestamp.now()
})

2022 EDIT:

For newer version of Firebase ^10.0.2; Timestamp can be imported directly

import * as admin  from "firebase-admin";
import { Timestamp } from "firebase-admin/firestore"; 
 
admin.firestore().collection("name").set({
   date: Timestamp.now(),
})

Assassin answered 7/11, 2020 at 21:37 Comment(2)
Is there a well-known pattern to re-use Firestore code that uses Timestamp from a common dependency codebase?Birck
What exactly do you mean?Assassin
D
0

There is a difference in how the client side and server side packages format Timestamp for some reason.

client

import { Timestamp } from '@angular/fire/firestore';
[

    "LastEdited": {
        "seconds": 1709272799,
        "nanoseconds": 999000000
    }
]

server

import { Timestamp } from 'firebase-admin/firestore';

[

    "LastEdited": {
        "_seconds": 1709272799,
        "_nanoseconds": 999000000
    }
]

client solution when querying from server

manually create the Timestamp from the return

const timestamp = new Timestamp(data.LastEdited._seconds, data.LastEdited._nanoseconds);
Divinize answered 31/10, 2022 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.