Trying to find out the new way to show a timestamp in collections, usually it just used to be
timestamp: firebase.firestore.FieldValue.serverTimestamp()
im using the timestamp key aswell if that changes anything, I cannot find it anywhere, apparently they updated it as there was an issue?
db.collection('posts').add({
message: input,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
profilePic: user.photoURL,
username: user.displayName,
image: image,
})
Thanks
Related
I'm learning firestore recently.
I want to implement below data structure.
- user (document)
- schedules(field, array)
- 0(map)
- startTime(tiemstamp)
- endTime(timestamp)
- 1(map)
- startTime(tiemstamp)
- endTime(timestamp)
I wanted to operate adding a testdata in firestore's GUI. so I created a schedules(array) and 0(map)'s data(include startTime and endTime). after that I added 1(map)'s data(include startTime and endTime). At that moment, 0(map)'sdata was automatically changed to below data structure.
- 0(map)
- startTime(object)
- nanoseconds(number) (changed to 0)
- seconds(number) (changed to 1550502000)
- endTime(object)
- nanoseconds(number) (changed to 0)
- seconds(number) (changed to 1550504000)
- 1(map)
- startTime(tiemstamp)
- endTime(timestamp)
why timestamp was automatically changed to object?
Please teach me.
I got to reproduce the problem, it seems to be a bug with the Firebase console, not with Firestore itself, because it only happens on the console.
You should report it to Google: https://firebase.google.com/support/contact/
In the meantime, though, what you can do is add the test data through code, using any language that supports the Admin SDK.
Example in Node:
import admin from 'firebase-admin';
admin.initializeApp();
// ...
await admin.firestore().collection('test-date').add({
schedule: [
{
startDate: Timestamp.fromDate(new Date()),
endDate: Timestamp.fromDate(new Date()),
},
{
startDate: Timestamp.fromDate(new Date()),
endDate: Timestamp.fromDate(new Date()),
},
]
});
I'm using functions.auth.user().onCreate() as part of a firestore project, and trying to set up some default data when a new user registers. For the front end, I'm using firebase-ui, with Google and Email/Password providers enabled.
When I sign in with an email and password, the UI widget prompts to enter a name and set a password. I was expecting to see the name as part of the user parameter in the onCreate() function call, but I'm getting practically nothing:
user: { email: 'xxx#yyyy.co.uk',
emailVerified: false,
displayName: null,
photoURL: null,
phoneNumber: null,
disabled: false,
providerData: [],
customClaims: {},
passwordSalt: null,
passwordHash: null,
tokensValidAfterTime: null,
metadata:
UserRecordMetadata {
creationTime: '2018-11-20T15:06:01Z',
lastSignInTime: '2018-11-20T15:06:01Z' },
uid: 'QDJ5OJTwbvNo2QNDVQV9VsxC2pz2',
toJSON: [Function] }
Not even getting the provider info so I can tell which 'kind' of user registered. It's almost like this function is triggered before the user record has been populated (except the email address does get through). Also, registrations via the Google provider come with a fully-populated user record, so I guess this is a problem with Email/Password specifically.
Is this a bug, or am I missing something? I didn't see anything else useful in the context parameter either.
The fact that displayName is not populated in the Cloud Functions onCreate trigger for email+password is expected. The function is triggered from the first API call (createUserWithEmailAndPassword()), while the display name is set with a second API call (updateProfile).
The usual workaround would be to create a Cloud Function to update the user profile, as shown here: Firebase Auth+Functions | create user with displayName
I also highly recommend filing a feature request to be able to have a Cloud Function triggered on profile changes.
Edit: See solution at the end
My guess was to put the model (in my case 'user') inside => type, but then it'll say "Assertion failed, you need to pass a model ..."
I do have a user.js in app/models
here's an excerpt from the router (after login function)
self.store.push({
data: {
id: data.currentUser.uid,
type: 'user',
attributes: {
displayName: data.currentUser.displayName,
email: data.currentUser.email,
photoURL: data.currentUser.photoURL,
firebaseUID: data.currentUser.uid,
rank: "scorer",
status: "active",
loginCount: 0,
provider: provider,
timestamp: new Date().getTime()
}
}
});
and here's my model (user.js in app/models)
import DS from 'ember-data';
export default DS.Model.extend({
displayName: DS.attr('string'),
email: DS.attr('string'),
photoURL: DS.attr('string'),
firebaseUID: DS.attr('string'),
rank: DS.attr('string'),
status: DS.attr('string'),
loginCount: DS.attr('string'),
provider: DS.attr('string'),
timestamp: DS.attr('number')
});
Please help :( thanks everyone in advance!
Edit => Solution that worked: If you do a createRecord and match the "id:" attribute, it will update the record with the same id (will work if you specified your own id). However, I'm not sure yet how to update a record if you let the system generate an ID for you. I assume that you would have to extract the ID first. But I haven't tested that idea yet. If someone would be so kind to test it, that'll be awesome.
Instead of pushing the raw data, create a model and run its save method.
var user = this.store.createRecord('user', {
displayName: data.currentUser.displayName,
// set more properties here
})
user.save()
This way, Emberfire and Ember Data can do their thing and ensure the data is formatted correctly. Also see
https://github.com/firebase/emberfire/blob/master/docs/quickstart.md#5-save-data
https://guides.emberjs.com/v3.0.0/models/creating-updating-and-deleting-records/
https://guides.emberjs.com/v3.0.0/models/pushing-records-into-the-store/
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
export default functions.auth.user().onCreate(saveUserToDatabase);
async function saveUserToDatabase(event) {
const Users = admin.database().ref('Users');
const authUser = event.data;
let user = await Users.child(authUser.uid).set({
createdAt: authUser.metadata.createdAt.toString(),
email: authUser.email,
facebookId: authUser.providerData[0].uid.replace('http://facebook.com/', ''),
lastSignedInAt: authUser.metadata.lastSignedInAt.toString(),
name: authUser.displayName,
photoUrl: authUser.photoURL,
});
console.log('saveUserToDatabase()');
console.log(authUser);
}
In the above code I save a user to the firebase database when they register. Now unless I use the toString method on the dates they do not save. I looked into this a little further and found that the dates don't come in as strings and that is causing some issues. (I did this with console.log and checking the firebase dashboard)
{ displayName: 'Test User',
email: 'test#example.com',
metadata:
{ createdAt: 2017-05-02T05:18:45.000Z,
lastSignedInAt: 2017-05-02T05:18:45.000Z }
}
When I use the toString method though it converts the output to:
"Tue May 02 2017 05:24:31 GMT+0000 (UTC)"
Dates are also saved in some instances in this format:
"1492213242000"
Why is there so many timestamp formats?
What is the preferred timestamp format for firebase I should be using?
How do I convert the dates into the preferred timestamp using cloud functions?
The object you're receiving in event.data is an admin.auth.UserRecord. Its interface specifies that the createdAt and lastSignedInAt timestamps should be JavaScript Date objects.
The Date type has enough issues that we try to avoid it in newer interfaces. I suspect you may be hitting some of those pain points in the inconsistent toString() serialization.
I agree with Doug that for storage, milliseconds since the epoch should be the preferred format. You should be able to get that from createdAt.value, for example.
I'm using Meteor's account-entry package to handle the signin-signup action of my web app. To add a Confirm Password field to the sign up form, this is what I've done (in CoffeeScript):
AccountsEntry.config
logo: '/logo.png'
homeRoute: 'main'
dashboardRoute: 'main'
profileRoute: '/profile'
extraSignUpFields: [
field: "confirmPassword"
label: "Confirm Password"
type: "password"
,
field: "name"
label: "Full Name"
placeholder: "Full Name"
type: "text"
required: true
,
field: "position"
label: "Position"
placeholder: "Developer"
type: "text"
]
The problem with this approach is that: it also save the confirmPassword field to the database, so that when someone access the database > users collection, they can clearly see every users' password in confirmPassword field - which is very bad.
I don't know how to fix this problem yet. I think there may be an attribute which decide whether a specific field should be store in the database or not, but I haven't figured it out yet ! (the accounts-entry package documentation seems not detailed enough to me, I have to say :( )
Can you guys help me with this problem ? Thanks so much in advance !
The lack of a password confirmation field is a known issue with accounts-entry.
On the other hand, the publish function for the users collection should only publish the strictly necessary fields. By default, only username, emails and profile are published to the client.
Anyway, you should not store the confirmPassword in the database to begin with. To do that, hook into Accounts.onCreateUser and delete that field before returning the user object:
Accounts.onCreateUser(function (options, user) {
delete user.confirmPassword; // or: delete user.profile.confirmPassword;
return user;
});