I'm linking the FB Graph API to Meteor so that I can retrieve a users photos and I'm having trouble setting the Meteor id to the Facebook id for each photo. Right now when the function is called it will return the same photo multiple times in the database since Meteor assigns a new _id to each photo each time.
For example, one entry might look like this:
Object {_id: "cnMsxSkmMXTjnhwRX", id: "1015160259999999", from: Object, picture: "https://photoSmall.jpg", source: "https://photoBig.jpg"…}
And a second, after the call has been performed again, like this:
Object {_id: "acMegKenftmnaefSf", id: "1015160259999999", from: Object, picture: "https://photoSmall.jpg", source: "https://photoBig.jpg"…}
Thereby creating two id fields in MongoDB.
The code I am using is below. I've tried a number of things to fix the code to no avail.
Meteor.methods({
getUserData: function() {
var fb = new Facebook(Meteor.user().services.facebook.accessToken);
var data = fb.getUserData();
_.forEach(data.data, function(photo) {
Photos.insert(photo, function(err) {
if(err) console.error(err);
});
});
}
});
Thanks in advance!
Check if the photo exists prior to inserting it
...
_.forEach(data.data, function(photo) {
if(Photos.findOne({id: photo.id})) return;
...
Another option is to add a unique key index to the id field. Or even use the _id field to store the id value. (be sure to use try catch to ensure it doesn't cause an error on the second insert).
Wouldn't there be something different to each of these with different ids?
You could also clean up the uniques before you run them with _.uniq
Related
I have data model like this
Players-->root collection
Sports--->root collection
Players_Sports---root collection
I want get all the sports(Multiple sport) details or document player belongs.
For this I am using angularFireStore5
First, I am getting
Player details like this
this.db.collection('players').doc(id).get().toPromise()
Second, I am getting Player(user) linked PlayerSport
db.collection<any>('PlayerSports',ref => ref.where('playerId', '==', id) ).get().toPromise()
Third, I am trying to get Sports details based on ID'S,
db.collection<any>('sportsType', ref => ref.where('sportsType' 'in' [sportsIDs])).get().toPromise()
where SportIDs is arrary of ID that are linked in player_sports
First and Second steps works fine, but third steps is not giving any data or response
Could you please let me know where is the problem,
is it in Data model or code? my guess is that data model is not correct. Please guide me on this.
I would suggest getting the data from firebase and storing it inside a list so the app can access it later.
void getDataF(){
databaseReference
.collection("TableName")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) {
iDFacList.add(f.documentID);
dbFacList.add(f.data["FieldName"]);
});
});
}
There is no sportsType field in the sportsType document as far as I can see.
If you're trying to find documents based on their SportsId field, you'll want ref.where('SportsId'....
Update
It seems that you're trying to find a document by its ID, which you can do with:
ref.doc(sportsIDs)
If you want to get multiple documents, or get a single document as a collection, you can use:
ref.where(firebase.firestore.FieldPath.documentId() 'in' [sportsIDs])
I have something like the following code:
User.findOne(id)
.exec((err, user) => {
Pets.find(_.pluck(user.pets, 'id'))
.populate("toys")
.exec((err, petsWithToys) => {
user.pets = petsWithToys;
return res.ok({ user: user });
});
});
When I look at the response in the client I don't see the toys array inside the pet.
I thought maybe this was due to overriding the toJSON function in my User model but even when removing it I get the same behavior.
Also, I've found out that if I assign the values to a new property that is not defined in the model, I do see the values at the client. I.e. if I do
user.petsNew = petsWithToys;
I will see the fully populated property.
I've seen the documentation of toObject where is says it removes instance methods (here) but I am not sure why the collection is considered a method and don't understand how after changing the value it is still removed.
Any comments/explanations/workarounds?
P.S. Tried to step through the code but can't step into toObject...
Add user = user.toJSON(); before user.pets = petsWithToys;
Check https://stackoverflow.com/a/43500017/1435132
I'm using meteor and meteor.angular.
I have a list of documents which are published by meteor with a restricted number of fields, since I don't need the full objects just for the list.
Meteor.publish("trackers", function () {
return Trackers.find({},
{fields:
{
'projectTracker.projectSPID':1,
'projectTracker.projectName':1,
'projectTracker.date':1
}
});
});
Then, clicking through on one of the list items, I use the object's _id to subscribe to a second Meteor.publish that I hoped would return the full object.
Meteor.publish("trackerBy_id", function (id) {
return Trackers.find({
'_id': id
});
});
But, the _id is already with the client data, there is no update and I just get the limited object I was using for the original list rather than the single full object.
Using url params does cause the full object to be published.
Meteor.publish("trackerBy_params", function (SPID,date) {
return Trackers.find({
'projectTracker.projectSPID': SPID,
'projectTracker.date': date
});
});
How can I use _id when a limited dataset already exists and trigger Meteor to publish the full object?
First off, some background
My client has a kind of a "split-view", meaning- a side-panel displaying a list of objects and a main view displaying the selected object's details. Every time the user clicks on an Object in the list, a Backbone's route is called to navigate to the id which updates a "selected" property on the Session, what causes the main view to update- pretty standard stuff.
The problem
I want the client to be as responsive as possible, therefore i'm trying to utilize Meteor's abillity to update the client immediately without waiting for a server confirmation.
My goal is that every time an Object is created, the list and the main view will be instantly updated to reflect the newly added Object. To achieve this I created a Meteor.method, create(), that uses Collection.insert and returns the id so I can use it with my Route. The method is shared across the client and server and is being called from within a template's event handler.
My first try was to store the returned id in a variable in the event handler and update the Route in the next line; For some reason, that didn't work because the method returned an undefined value. So I tried a different approach, instead of returning the id, I used it within the method to update the Route directly (if Meteor.isClient of course). That didn't work either because the id returned by Collection.insert in the client's version of the method was different from the one in the server's version.
First approach
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
var objectId = Meteor.call('create');
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
});
Second approach
Meteor.methods({
create: function () {
var ObjectId = Objects.insert({name:'test'});
if(Meteor.isClient){
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
}
});
If anyone knows what's going on and can give me some directions that would be great.
Any different approaches to the problem or suggestions would be much appreciated as well.
Thanks
Update
So I tried #Pent's suggestion and I got the same result as with my second approach. For some odd reason Meteor decides to ignore my id (created with Random.id()) and inserts the object with a different one.
So I tried another approach, I used just a simple string value instead of Random.id() and voila - it worked. Riddle me that.
Answer updated:
This will be both a client and server method:
Meteor.methods({
create: function () {
var id = Random.id();
Objects.insert({_id: id, name:'test'});
if(this.isSimulation) {
appRouter.navigate("object/id/" + id, {trigger:true});
}
}
});
You can view a similar pattern from Meteor's party example: https://github.com/meteor/meteor/blob/b28c81724101f84547c6c6b9c203353f2e05fbb7/examples/parties/model.js#L56
Your problem is coused by the fact that remote methods, i.e. those which will be called on the server, don't simply return any value. Instead, they accept a callback that will be used to process the returned value (see docs). So in your first example you should probably do something like this:
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
Meteor.call('create', function (error, result) {
if (!error)
appRouter.navigate("object/id/" + result, {trigger:true});
});
}
});
You also said:
I want the client to be as responsive as possible, therefore i'm trying to utilize Meteor's abillity to update the client immediately without waiting for a server confirmation.
I think that in this case you should definitely wait for server response. Note, that there is no chance you get the correct object id unless this is given to you by the server.
One possible way to get around this issue is to create a local (client-side) collection:
// only on client
var temporary = new Meteor.Collection(null); // null name
in which you could store your "temporary" newly created objects, and then save them to the "real" collection after the user clicks the save button. You could implement your router to respond to urls like object/new/* to get access to these objects before they're saved to your database.
The correct answer for this question is defining a client side method that's responsible for creating the unique id (preferably using Random.id() ) and calling the Meteor.methods' create(). That way, you can have the id available immediately without waiting for the server to generate one. The trick here is to generate the id outside of the Meteor.method so that the id generation happens only once for both the stub and the actual server method.
create = function(){
var id = Random.id();
Meteor.call('create', id);
return id;
}
Meteor.methods({
create: function (id) {
Objects.insert({_id: id, name:'test'});
//more code...
}
});
//and in the Template...
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
var objectId = create();
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
});
I have some code where I want a NoteCollectionView to add a new Note to the NoteCollection. This is triggered by a function newNote in the NoteCollectionView:
newNote: function(data) {
var note = new Note(data);
this.collection.add(note);
},
I'm still very new to backbone, and I want to make sure this syncs with the server. The concerns I have are:
1) Will simply adding this note to the collection trigger a save() from the server, and update the model with the ID that the server gives it? Or,
2) If the server does not update my model and give me an actual ID, how do I save the model with note.save() and get back an ID from the server?
To address your first question, no, .add will not trigger any kind of call to the server; it will only add a model to a collection.
However, you do have a couple options. One would be to create the new note model, save it to the database, and then add it to the collection:
newNote: function(data) {
var note = new Note(data);
note.save();
this.collection.add(note);
}
The second option is to simply use Backbone's collection.create method. Give it a hash of attributes and it will
Create the model
Save it to the database
Add it to the collection
All in one fell swoop, like so:
newNote: function(data) {
return this.collection.create(data);
}
collection.create also returns the newly created model, illustrated by my return statement above.