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/
Related
I'm having this issue while I'm trying to perform a crud update function. To put into context, this is an Ionic app with Firebase. This is an app in which the user will be able to create events and update them at a later stage if they want. However, I'm not being able to perform the update with the following error:
ERROR FirebaseError: Function DocumentReference.update() called with invalid data. Nested arrays are not supported (found in document Events/XWtRgH04iEG9IUIqMrgX)
Below are highlighted the function that will save an event after being updated and the service that contains the update function. Any help is greatly appreciated!
saveEvent(event) {
let id = event.id;
let evtSave = {
id: id,
createdAt: event['createdAt'],
createdBy: event['createdBy'],
updatedAt: Date.now(),
part: event['part'] || ['No participants'],
comments: event['comments'] || ['No comments'],
type: event['type'],
title: event['title'],
date: event['date'],
time: event['time'],
map: event['map'],
players: event['players'],
location: event['location'],
description: event['description'],
image: event['image']
};
console.log('saveEvent: ', evtSave);
this.eventServ.updateEvents(id, evtSave)
.then(res => {
this.searchEvents();
console.log('Event: ', res);
this.myAlert('Event successfully updated');
this.mode = 'listMode';
});
Below is the code contained in the service:
updateEvents(eventID, event){
return this.firestore.collection('Events').doc(eventID).update(({
id: event.id,
createdAt: event.date,
createdBy: event.createdBy,
updatedAt: Date.now(),
part: [event.part],
comments: [],
type: event.type,
title: event.title,
date: event.dateMilis,
time: event.time,
map: event.map,
players: event.players,
location: event.location,
description: event.description || 'No description...',
image: event.image || 'No image...',
})).catch((error)=>{
console.log('Error: ', error);
})
and finally a screenshot of how an event looks like in firebase:
At one place in your code you have part: event['part'] || ['No participants'], which will set part to an array of stringy, containing exactly one participant.
Later, when you save, you do: part: [event.part], which I assume can lead to the case where you will get part: [['No participants']].
This is a nested array and as firebase tells you in the error message, this is not supported in firestore.
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
I'm writing a meteor app and I'm trying to add an autocomplete feature to a search box. The data is very large and is on the server, so I can't have it all on the client. It's basically a database of users. If I'm not wrong, the mizzao:autocomplete package should make that possible, but I can't seem to get it to work.
Here's what I have on the server:
Meteor.publish('autocompleteViewers', function(selector, options) {
Autocomplete.publishCursor(viewers.find(selector, options), this);
this.ready();
});
And here are the settings I use for the search box on the client:
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
options: '',
template: Template.vLegend
}],
};
}
But I keep getting this error on the client:
Error: Collection name must be specified as string for server-side search at validateRule
I don't really understand the problem. When I look at the package code, it just seems like it's testing whether the subscription field is a string and not a variable, which it is. Any idea what the problem could be? Otherwise is there a minimum working example I could go from somewhere? I couldn't find one in the docs.
Error: Collection name must be specified as string for server-side search at validateRule
You get this error because you don't specify a Collection name in quotes.
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
collection: 'viewers', // <- specify your collection, in your case it is a "viewers" collection.
options: '',
template: Template.vLegend
}],
};
}
For more information please read here.
Hope this helps!
I am new to firebase, and wondering how I can implement deleting the data in Angular view (interface), but still keep it in the Firebase database. Currently, due to the three way binding (use Firebase.remove() function), the data will be deleted in the database when it is deleted in Angular view. See in Plunker here:
http://plnkr.co/edit/BBtD2YoUBHBAyhu0puXd?p=info
Here is the remove user part:
// Remove user
$scope.removeRecord = function(userId) {
var userUrl = fbURL + user_table + '/' + userId;
$scope.user = $firebase(new Firebase(userUrl));
$scope.user.$remove()
$scope.alerts.splice(0, 1);
$scope.alerts.push({
type: 'success',
msg: "User removed successfully!"
});
};
Or is that possible I can retrieve a data from Firebase based on my custom query? So maybe I can distinguish the deleted data from the existing data in Firebase database?
because i want to have all the data in database even it is get deleted
This is typically referred to as a "soft delete" and it essentially means you simply mark the data as "deleted.
Say you have this data:
messages
-J4378sdfisdf
name: "Lisa"
message: "I am new to firebase, and wondering..."
-J4378sdfjteg
name: "Chrillewoodz"
message: "Try doing this instead..."
-J4378sdfkufh
name: "Frank van Puffelen"
message: "This is typically referred to as a..."
Instead of only removing the messages from view, you instead mark them as "deleted"/hidden. In the sample below, I added a visible field for the purpose:
messages
-J4378sdfisdf
name: "Lisa"
message: "I am new to firebase, and wondering..."
visible: true
-J4378sdfjteg
name: "Chrillewoodz"
message: "Try doing this instead..."
visible: true
-J4378sdfkufh
name: "Frank van Puffelen"
message: "This is typically referred to as a..."
visible: false
And then you can use a Firebase query to get only the messages that have not been hidden:
var ref = new Firebase('https://yours.firebaseio.com');
var query = ref.child('messages').orderByChild('visible').equalTo(true);
$scope.messages = $firebaseArray(query);
Try doing this instead:
<button ng-click="removeRecord(user)">Delete</button>
$scope.removeRecord = function(user) {
user.remove();
$scope.alerts.splice(0, 1);
$scope.alerts.push({
type: 'success',
msg: "User removed successfully!"
});
};
This way you're not accessing the user in Firebase, but in the view instead.
You should pass the user object into the function instead of its ID. The way you were doing it you were accessing the user in Firebase rather in the view only.
In the new Meteor auth branch how can I create users server side?
I see how to create them client side with the call to
[Client] Meteor.createUser(options, extra, callback)
But suppose I want to create a Meteor user collection record on startup?
For example, the Administrator account during startup/bootstrapping for an application?
Thanks
Steeve
On newer versions of meteor use
Accounts.createUser({
username: username,
email : email,
password : password,
profile : {
//publicly visible fields like firstname goes here
}
});
note: the password hash is generated automatically
On older versions of meteor use:
1 - NB: DO YOU HAVE THE REQUIRED PACKAGES INSTALLED ?
mrt add accounts-base
mrt add accounts-password
On some versions of meteor you cannot call SRP password salt generator as Steeve suggested, so try this:
2 - do Meteor.users.insert( )
e.g.
var newUserId =
Meteor.users.insert({
emails: ['peter#jones.com'],
profile : { fullname : 'peter' }
});
note: a user must have EITHER a username or an email address. I used email in this example.
3 - Finally set the password for the newly created account.
Accounts.setPassword(newUserId, 'newPassword');
Probably it's a well known fact now, but for the sake of completing this - there's a new server API for doing this on the auth branch. From the docs on auth:
" [Server] Meteor.createUser(options, extra) - Creates a user and
sends that user an email with a link to choose their initial password
and complete their account enrollment
options a hash containing: email (mandatory), username (optional)
extra: extra fields for the user object (eg name, etc). "
Please note the API is subject to change as it's not on the master branch yet.
For now this has been suggested in the meteor-core google group.
Meteor.users.insert({username: 'foo', emails: ['bar#example.com'], name: 'baz', services: {password: {srp: Meteor._srp.generateVerifier('password')}}});
It works. I tested it in during startup/boot strap.
I would not consider this the permanent or long term answer because I believe the auth branch is still in a great degree of change and I imagine the team behind Meteor will provide some kind of functionality for it.
So, do not depend on this as a long term answer.
Steeve
At the moment, I believe you cannot. Running
Meteor.call('createUser', {username: "foo", password: "bar"});
comes close, but the implementation of createUser in passwords_server.js calls this.setUserId on success, and setUserId cannot be called on the server unless we're in a client-initiated method invocation (search for "Can't call setUserId on a server initiated method call" in livedata_server.js.
This does seem like something worth supporting. Perhaps the last three lines of createUser, which log the user in, should be controlled by a new boolean login option to the method? Then you could use
Meteor.call('createUser', {username: "foo", password: "bar", login: false});
in server bootstrap code.
I've confirmed that the following code in my server/seeds.js file works with the most recent version of Meteor (Release 0.8.1.1)
if (Meteor.users.find().count() === 0) {
seedUserId = Accounts.createUser({
email: 'f#oo.com',
password: '123456'
});
}
Directory (or folder) of server means I'm running the code on the server. The filename seeds.js is completely arbitrary.
The official documentation now describes both the behavior for Accounts.createUser() when run on the client and when run on the server.
Working coffeescript example for Meteor version 1.1.0.2 (server side):
userId = Accounts.createUser
username: 'user'
email: 'user#company.com'
password: 'password'
profile:
name: 'user name'
user = Meteor.users.findOne userId
I struggled for some time with this API getting 'User already exists' exception in working code before adding profiles.name to the options and exception disappeared.
reference: Accounts.createUser(options,[callback])
Create user from server side
// Server method
Meteor.methods({
register: function(data) {
try {
console.log("Register User");
console.log(data);
user = Accounts.createUser({
username: data.email,
email: data.email,
password: data.password,
profile: {
name: data.email,
createdOn: new Date(),
IsInternal: 0
}
});
return {
"userId": user
};
} catch (e) {
// IF ALREADY EXSIST THROW EXPECTION 403
throw e;
}
}
});
// Client call method
Meteor.call('register',{email: "vxxxxx#xxxx.com",password: "123456"}, function(error, result){
if(result){
console.log(result)
}
if(error){
console.log(result)
}
});