Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit b325436

Browse files
How to set Firestore serverTimestamp on document create / update #736
1 parent 690850b commit b325436

9 files changed

Lines changed: 102 additions & 57 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
[Firebase Android SDK Changelog](https://firebase.google.com/support/release-notes/android)
55

66
## 6.1.0 (PENDING)
7-
8-
### Fixes
9-
- [#711](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues/711) Crashlytics: "Configure Crashlytics" build step phase added multiple times
7+
[Fixes & Enhancements](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/milestone/57)
108

119

1210
## 6.0.2 (2018, May 16)

demo-ng/app/tabs/firestore/firestore.component.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,16 @@ export class FirestoreComponent {
4242

4343
public firestoreSet(): void {
4444
firebase.firestore().collection("dogs").doc("fave")
45-
.set({name: "Woofie", last: "lastofwoofie", date: new Date()}, {merge: true})
45+
.set({
46+
name: "Woofie",
47+
last: "lastofwoofie",
48+
// note that this only works on iOS (there's a limitation in the Firestore Android SDK)
49+
// updateTsSet: firebase.firestore().FieldValue().serverTimestamp()
50+
},
51+
{
52+
merge: true
53+
}
54+
)
4655
.then(() => {
4756
console.log("Woofie set");
4857
})
@@ -112,7 +121,11 @@ export class FirestoreComponent {
112121

113122
public firestoreUpdate(): void {
114123
firebase.firestore().collection("dogs").doc("fave")
115-
.update({name: "Woofieupdate", last: "updatedwoofie"})
124+
.update({
125+
name: "Woofieupdate",
126+
last: "updatedwoofie!",
127+
updateTs: firebase.firestore().FieldValue().serverTimestamp()
128+
})
116129
.then(() => {
117130
console.log("Woofie updated");
118131
})

demo/app/main-view-model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ export class HelloWorldModel extends Observable {
13591359
remoteFullPath: 'uploads/images/telerik-logo-uploaded.png'
13601360
}).then(
13611361
theUrl => {
1362+
console.log("Download url: " + theUrl);
13621363
alert({
13631364
title: "File download URL determined",
13641365
message: "You can download the file at: " + theUrl,

docs/FIRESTORE.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,17 @@ citiesCollection.doc("LA").set({
152152
```
153153

154154
### `collection.doc().update()`
155-
Update any number of properties of a document:
155+
Update any number of properties of a document.
156+
157+
Use the special property `firebase.firestore().FieldValue().serverTimestamp()` to update a server timestamp
158+
(as opposed to a local timestamp, which would be different for every client).
156159

157160
```typescript
158161
const sanFranciscoDocument = firebase.firestore().collection("cities").doc("SF");
159162

160163
sanFranciscoDocument.update({
161-
population: 860001
164+
population: 860001,
165+
updateTimestamp: firebase.firestore().FieldValue().serverTimestamp()
162166
}).then(() => {
163167
console.log("SF population updated");
164168
});
@@ -217,4 +221,4 @@ query
217221
```
218222

219223
## Future work
220-
Need something else that's not supported yet? Please open an Issue or PR 😚
224+
Need something else that's not supported yet? Please open an Issue or PR 😚

src/app/firestore/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import * as firebase from "../../firebase";
2+
import { FIRESTORE_SERVER_TS } from "../../firebase";
23

34
export module firestore {
45
export class Firestore {
56
collection(collectionPath: string): firebase.firestore.CollectionReference {
67
return firebase.firestore.collection(collectionPath);
78
}
9+
FieldValue(): firebase.firestore.FieldValue {
10+
return {
11+
serverTimestamp: () => FIRESTORE_SERVER_TS
12+
}
13+
}
814
}
915
}

src/firebase-common.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { prompt } from "tns-core-modules/ui/dialogs";
2-
import { firestore } from "./firebase";
2+
import { getString, setString } from "tns-core-modules/application-settings";
3+
import { firestore, FIRESTORE_SERVER_TS } from "./firebase";
34
import * as analytics from "./analytics/analytics";
45
import * as mlkit from "./mlkit";
5-
import * as applicationSettings from "tns-core-modules/application-settings";
6+
7+
// note that this implementation is overridden for iOS
8+
export class FieldValue {
9+
serverTimestamp = () => FIRESTORE_SERVER_TS;
10+
}
611

712
export const firebase: any = {
813
initialized: false,
@@ -14,7 +19,9 @@ export const firebase: any = {
1419
_dynamicLinkCallback: null,
1520
analytics,
1621
mlkit,
17-
firestore: {},
22+
firestore: {
23+
FieldValue
24+
},
1825
invites: {
1926
MATCH_TYPE: {
2027
WEAK: 0,
@@ -103,10 +110,10 @@ export const firebase: any = {
103110
});
104111
},
105112
rememberEmailForEmailLinkLogin: (email: string) => {
106-
applicationSettings.setString("FirebasePlugin.EmailLinkLogin", email);
113+
setString("FirebasePlugin.EmailLinkLogin", email);
107114
},
108115
getRememberedEmailForEmailLinkLogin: () => {
109-
return applicationSettings.getString("FirebasePlugin.EmailLinkLogin");
116+
return getString("FirebasePlugin.EmailLinkLogin");
110117
},
111118
strongTypeify: value => {
112119
if (value === "true") {

src/firebase.android.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { DocumentSnapshot, firebase, QuerySnapshot } from "./firebase-common";
22
import * as appModule from "tns-core-modules/application";
33
import { AndroidActivityResultEventData } from "tns-core-modules/application";
4-
import * as utils from "tns-core-modules/utils/utils";
4+
import { ad as AndroidUtils, layout } from "tns-core-modules/utils/utils";
55
import lazy from "tns-core-modules/utils/lazy";
6-
import * as frame from "tns-core-modules/ui/frame";
7-
import * as fs from "tns-core-modules/file-system";
8-
import { firestore } from "./firebase";
6+
import { topmost } from "tns-core-modules/ui/frame";
7+
import { File } from "tns-core-modules/file-system";
8+
import { firestore, FIRESTORE_SERVER_TS } from "./firebase";
99

10-
declare const com, org: any;
10+
declare const android, com, org: any;
1111

1212
firebase._launchNotification = null;
1313
firebase._cachedDynamicLink = null;
@@ -126,12 +126,16 @@ firebase.toHashMap = obj => {
126126
if (obj[property] === null) {
127127
node.put(property, null);
128128
} else {
129-
if (obj[property] instanceof Date) {
129+
// note that the Android Firestore SDK only supports this for 'update' (not for 'set')
130+
if (obj[property] === FIRESTORE_SERVER_TS) {
131+
node.put(property, com.google.firebase.firestore.FieldValue.serverTimestamp());
132+
} else if (obj[property] instanceof Date) {
130133
node.put(property, new java.util.Date(obj[property].getTime()));
131134
} else if (Array.isArray(obj[property])) {
132135
node.put(property, firebase.toJavaArray(obj[property]));
133136
} else {
134137
switch (typeof obj[property]) {
138+
case 'object':
135139
case 'object':
136140
node.put(property, firebase.toHashMap(obj[property], node));
137141
break;
@@ -616,7 +620,7 @@ firebase.admob.showBanner = arg => {
616620
const ad = firebase.admob._buildAdRequest(settings);
617621
firebase.admob.adView.loadAd(ad);
618622

619-
const density = utils.layout.getDisplayDensity(),
623+
const density = layout.getDisplayDensity(),
620624
top = settings.margins.top * density,
621625
bottom = settings.margins.bottom * density;
622626

@@ -644,8 +648,8 @@ firebase.admob.showBanner = arg => {
644648
// Wrapping it in a timeout makes sure that when this function is loaded from a Page.loaded event 'frame.topmost()' doesn't resolve to 'undefined'.
645649
// Also, in NativeScript 4+ it may be undefined anyway.. so using the appModule in that case.
646650
setTimeout(() => {
647-
if (frame.topmost() !== undefined) {
648-
frame.topmost().currentPage.android.getParent().addView(adViewLayout, relativeLayoutParamsOuter);
651+
if (topmost() !== undefined) {
652+
topmost().currentPage.android.getParent().addView(adViewLayout, relativeLayoutParamsOuter);
649653
} else {
650654
appModule.android.foregroundActivity.getWindow().getDecorView().addView(adViewLayout, relativeLayoutParamsOuter);
651655
}
@@ -1154,7 +1158,7 @@ firebase.login = arg => {
11541158
arg.phoneOptions.phoneNumber,
11551159
60, // timeout (in seconds, because of the next argument)
11561160
java.util.concurrent.TimeUnit.SECONDS,
1157-
appModule.android.foregroundActivity, // or utils.ad.getApplicationContext()
1161+
appModule.android.foregroundActivity,
11581162
new OnVerificationStateChangedCallbacks());
11591163

11601164
} else if (arg.type === firebase.LoginType.CUSTOM) {
@@ -1215,7 +1219,7 @@ firebase.login = arg => {
12151219
if (arg.facebookOptions && arg.facebookOptions.scope) {
12161220
scope = arg.facebookOptions.scope;
12171221
}
1218-
const permissions = utils.ad.collections.stringArrayToStringSet(scope);
1222+
const permissions = AndroidUtils.collections.stringArrayToStringSet(scope);
12191223

12201224
const activity = appModule.android.foregroundActivity;
12211225
fbLoginManager.logInWithReadPermissions(activity, permissions);
@@ -1226,8 +1230,8 @@ firebase.login = arg => {
12261230
return;
12271231
}
12281232

1229-
const clientStringId = utils.ad.resources.getStringId("default_web_client_id");
1230-
const clientId = utils.ad.getApplicationContext().getResources().getString(clientStringId);
1233+
const clientStringId = AndroidUtils.resources.getStringId("default_web_client_id");
1234+
const clientId = AndroidUtils.getApplicationContext().getResources().getString(clientStringId);
12311235

12321236
// Configure Google Sign In
12331237
const googleSignInOptionsBuilder = new com.google.android.gms.auth.api.signin.GoogleSignInOptions.Builder(com.google.android.gms.auth.api.signin.GoogleSignInOptions.DEFAULT_SIGN_IN)
@@ -1967,7 +1971,7 @@ firebase.uploadFile = arg => {
19671971

19681972
} else if (arg.localFullPath) {
19691973

1970-
if (!fs.File.exists(arg.localFullPath)) {
1974+
if (!File.exists(arg.localFullPath)) {
19711975
reject("File does not exist: " + arg.localFullPath);
19721976
return;
19731977
}

src/firebase.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export declare const FIRESTORE_SERVER_TS = "SERVER_TIMESTAMP";
2+
13
/**
24
* The allowed values for LoginOptions.type.
35
*/
@@ -827,6 +829,10 @@ export namespace firestore {
827829
add(data: DocumentData): Promise<DocumentReference>;
828830
}
829831

832+
export class FieldValue {
833+
static serverTimestamp: () => FIRESTORE_SERVER_TS
834+
}
835+
830836
export interface QuerySnapshot {
831837
docSnapshots: firestore.DocumentSnapshot[];
832838

0 commit comments

Comments
 (0)