tag friend on a Post - tags

Hello I'm trying to taga friend in a wall post with officials graph api.
As reported on documentation
message_tags
Objects tagged in the message (Users, Pages, etc) (Requires access_token)
object containing fields whose names are the indexes to where objects are mentioned in the message field; each field in turn is an
array containing an object with id, name, offset, and length fields,
where length is the length, within the message field, of the object
mentioned
var array = {'data':{'id':XXXXXXXXXX, 'name':'Friend name','offset':0,'length':11}};
Facebook.code.WallPost({
"access_token" : Titanium.App.Properties.getString('access_token'),
"message" : $("#post_message").val(),
"message_tags" : array
});
Facebook.code.WallPost is a custom javascript function to post.
WallPost : function(data) {
$.ajax({
type : "POST",
dataType : "json",
url : "https://graph.facebook.com/me/feed",
data : data,
success : function(data) {
alert("posted");
},
error : function(data) {
alert("not posted");
}
});
}
With my code post has been published but without tag!
Someone can help me?
Thank you, Stefano

The story_tags field contains information about the people and pages tagged in the story, and is in exactly the same format as the existing message_tags field on the Post object. For example:
{
. . .
"story": "Dhiren Patel likes Marmot.",
"story_tags": {
"19": [
{
"id": 101961456910,
"name": "Marmot",
"offset": 19,
"length": 6
}
],
"0": [
{
"id": 1207059,
"name": "Dhiren Patel",
"offset": 0,
"length": 12
}
]
},
. . .
}
Each tag within the story_tags field is indexed by its offset to where the object is referenced within the story field.
More info: https://developers.facebook.com/blog/post/592/

its a readonly object. Try :
FB.api('/me/posts', { limit: 3 }, function(response) {
for (var i=0, l=response.length; i<l; i++) {
var post = response[i];
if (post.message) {
alert('Message: ' + post.message);
} else if (post.attachment && post.attachment.name) {
alert('Attachment: ' + post.attachment.name);
}
}
});
And set a breakpoint and read the response object, it contains the message_tags.
/J

Related

MongoDB - Meteor : Update, add and delete an element from an array

I am trying to select a specific element in an nested array in a hash like so.
post:{
_id,
comments:[{
comment_id:post.comments.length + 1,
comment: "hello world",
user_id:Meteor.userId()}]
}
My ultimate goal is to be able to add/edit/delete the nested comment by comment_id but I am having trouble trying to select the element I need in the first place.
If you only have comments in your post object you should only have a comments array like this:
Posts {
_id: String;
comments: [];
}
And to delete a comment by his id :
Posts.update({_id: postId, "comments.comment_id" : "commentIdToDelete"},
{ $pull:{"comments": {"comment_id": "commentIdToDelete"}}})
To update a comment by his id :
Posts.update({_id: postId, "comments.comment_id" : "commentIdToUpdate"},
{ $set:{"comments.$.comment": "A new comment"}})
UPDATE
In order to add a comment in the comments array we have to initialiaze the post document (if it's not already done):
Posts.insert({
comments: []
});
Now we have to retrieve the comments array size of the post to update:
let lengthComments = Posts.findOne({_id: postIdToUpdate}).comments.length;
And finally we can add a comment in the comments array:
Posts.update({_id: postIdToUpdate}, {
$push: {
"comments": {
"comment_id": lengthComments + 1,
"comment": "My comment",
"user_id": Meteor.userId(),
}
}
});

How to replace prefetch source in Bloodhound with a 'real time' alternative?

I've been using Bloodhound with the prefetch [docs] option defined.
This works fine, except when I add content to the json file being prefetched, it is not available as a search result unless I restart the browser.
So I am trying to make the search results reflect the updated file content in 'real time'.
I tried simply replacing prefetch with remote but this causes the search functionality not to work as intended (it shows non-matched results).
Below is the code I am using with prefetch.
Version info: typeahead.bundle.min.js at v0.10.5.
function searchFunction() {
var template =
"<p class=\"class_one\">{{area}}</p><p class=\"class_two\">{{title}}</p><p class=\"class_three\">{{description}}</p>";
var compiled_template = Hogan.compile(template);
var dataSource = new Bloodhound({
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d.tokens.join(
' '));
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: '/static/my_file.json'
# remote: '/search'
});
dataSource.initialize();
$('.my_lookup .typeahead').typeahead({}, {
source: dataSource.ttAdapter(),
name: 'courses',
displayKey: 'title',
templates: {
suggestion: compiled_template.render.bind(
compiled_template)
}
}).focus().on('typeahead:selected', function(event, selection) {
var title = selection.title
// do things with the title variable
});
}
Edit:
I started thinking perhaps I need some server side logic to perform a search on a database that contains the content previously within the local json file.
Using the code posted below, the following works:
Searches database in real time.
All matches are returned.
The following does not work:
It does not offer suggestions, you have to type the full token name.
If searching for apple, it will search after typing a, then p etc, if it doesn't get any results, it shows this error in Firebug: TypeError: data is null. After a few of these errors, it stops triggering searches and no error is displayed.
And, the results from the database are in the following format, and I don't know how to apply the Hogan template for the suggestions to each result:
{
"matches": [{
"tokens": ["apple", "orange"],
"area": "Nautical",
"_id": {
"$oid": "4793765242f9d1337be3d538"
},
"title": "Boats",
"description": "Here is a description"
}, {
"tokens": ["apple", "pineapple"],
"area": "Aviation",
"_id": {
"$oid": "4793765242f9d1337be3d539"
},
"title": "Planes",
"description": "Here is a description."
}]
}
JS
function searchFunction() {
var engine = new Bloodhound({
remote: {
url: '/search?q=%QUERY%',
wildcard: '%QUERY%'
},
datumTokenizer: Bloodhound.tokenizers.whitespace('q'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
});
engine.initialize();
$('.my_lookup .typeahead').typeahead({
}, {
source: engine.ttAdapter(),
name: 'courses',
displayKey: 'title',
templates: {
suggestion: function (data) {
return "// not sure how to apply markup to each match"
}
}
}).focus().on('typeahead:selected', function(event, selection) {
console.log(selection);
var title = "// again not sure how to access individual match data"
// do things with the title variable
});
}
MongoDB Schema
Database: courses
Collection: courses
Documents:
{
"_id" : ObjectId("4793765242f9d1337be3d538"),
"tokens" : [
"apple",
"orange"
],
"area" : "Nautical",
"title" : "Boats",
"description" : "Here is a description."
}
and:
{
"_id" : ObjectId("4793765242f9d1337be3d539"),
"tokens" : [
"apple",
"pineapple"
],
"area" : "Aviation",
"title" : "Planes",
"description" : "Here is a description."
}
etc
Python (using Bottle routes)
#route('/search')
def search():
"""
Query courses database for matches in tokens field.
"""
# get the query
query = request.GET.q
# define the database
dbname = 'courses'
db = connection[dbname]
# define the collection
collection = db.courses
# make the query
matches = collection.find({"tokens":query})
# send back results
results = {}
results['matches'] = matches
response.content_type = 'application/json'
return dumps(results)

Elasticsearch for normalized data

I have some data from facebook api's...
I have a FB page and thats part of multiple country...
For example:-
Assume company-x operated in multiple countries - USA, UK, India, China
Now, a page can be posted on multiple country pages.
For example:- Company-x new innovation will be displayed in all the 4 country pages...
Each of the pages will get its over comments, likes...etc...
So, basically its a relational data.
Company(1) - Country(n)- Post(n) - LIkes(n) - Comments(n)...
I would like to know what would be the best way to store this data in elastic search and implement the search engine..
As you can't use "classic" (relational) JOINs in Elasticsearch, IMHO you only can choose between storing the (sub-)objects as flat objects, parent-child objects or nested objects in the index/type.
I think that you should consider the first two option. I personally would opt for flat objects, as they are easier to load, and also get returned from the FB Graph API in that way ("flat"). What you would have to add in you application is the mapping of the page to Company -> Country, because FB doesn't know about that.
See
https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-mapping.html
https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-mapping.html
As a query for the posts, you could use something like
/?ids={page1_id},{page2_id},{page3_id}&fields=id,posts.fields(id,message,created_time,link,picture,place,status_type,shares,likes.summary(true).limit(0),comments.summary(true).limit(0))
which will return something like
{
"id": "7419689078",
"posts": {
"data": [
{
"id": "7419689078_10153348181604079",
"message": "Gotta find them all in the real world soon.",
"created_time": "2015-09-10T06:40:12+0000",
"link": "http://venturebeat.com/2015/09/09/nintendo-takes-pokemon-into-mobile-gaming-in-partnership-with-google-niantic/",
"picture": "https://fbexternal-a.akamaihd.net/safe_image.php?d=AQDvvzpCAM1WkJZS&w=130&h=130&url=http%3A%2F%2Fi0.wp.com%2Fventurebeat.com%2Fwp-content%2Fuploads%2F2013%2F04%2Fpokemon_mystery_dungeon_gates_to_infinity_art.jpg%3Ffit%3D780%252C9999&cfs=1",
"status_type": "shared_story",
"likes": {
"data": [
],
"summary": {
"total_count": 0,
"can_like": true,
"has_liked": false
}
},
"comments": {
"data": [
],
"summary": {
"order": "ranked",
"total_count": 0,
"can_comment": true
}
}
}
],
"paging": {
"previous": "https://graph.facebook.com/v2.4/7419689078/posts?fields=id,message,created_time,link,picture,place,status_type,shares,likes.summary%28true%29.limit%280%29,comments.summary%28true%29.limit%280%29&limit=1&since=1441867212&access_token=&__paging_token=&__previous=1",
"next": "https://graph.facebook.com/v2.4/7419689078/posts?fields=id,message,created_time,link,picture,place,status_type,shares,likes.summary%28true%29.limit%280%29,comments.summary%28true%29.limit%280%29&limit=1&access_token=&until=1441867212&__paging_token="
}
}
}
You can then use some application-side JSON manipulation to
Add the Company -> Country -> Page mapping info to the JSON
Get rid of unwanted fields such as paging
Flatten the structure before saving (e.g. posts.data as posts)
before you save it to Elasticsearch. See the JSFiddle I prepared (fill in the access token!):
http://jsfiddle.net/7x9xuo8L/
Then, you can use the bulk load feature to load the data to Elasticsearch:
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
Sample JavaScript code:
var pageMapping = {
"venturebeat": {
"country": "United States",
"company": "Venture Beat"
},
"techcrunch": {
"country": "United States",
"company": "TechCrunch"
}
};
//For bulk load
var esInfo = {
"index": "socialmedia",
"type": "fbosts"
};
var accessToken = "!!!FILL_IN_HERE_BEFORE_EXECUTING!!!";
var requestUrl = "https://graph.facebook.com/?ids=venturebeat,techcrunch&fields=id,name,posts.fields(id,message,created_time,link,picture,place,status_type,shares,likes.summary(true).limit(0),comments.summary(true).limit(0)).limit(2)&access_token=" + accessToken;
$.getJSON(requestUrl, function(fbResponse) {
//Array to store the bulk info for ES
var bulkLoad = [];
//Iterate over the pages
Object.getOwnPropertyNames(fbResponse).forEach(function(page, idx, array) {
var pageData = fbResponse[page];
var pageId = pageData.id;
pageData.posts.data.forEach(function(pagePostObj, idx, array) {
var postObj = {};
postObj.country = pageMapping[page].country;
postObj.company = pageMapping[page].company;
postObj.page_id = pageData.id;
postObj.page_name = pageData.name;
postObj.post_id = pagePostObj.id;
postObj.message = pagePostObj.message;
postObj.created_time = pagePostObj.created_time;
postObj.link = pagePostObj.link;
postObj.picture = pagePostObj.picture;
postObj.place = pagePostObj.place;
postObj.status_type = pagePostObj.status_type;
postObj.shares_count = pagePostObj.shares.count;
postObj.likes_count = pagePostObj.likes.summary.total_count;
postObj.comments_count = pagePostObj.comments.summary.total_count;
//Push bulk load metadata
bulkLoad.push({ "index" : { "_index": esInfo.index, "_type": esInfo.type } })
//Push actual object data
bulkLoad.push(postObj);
});
});
//You can now take the bulkLoad object and POST it to Elasticsearch!
console.log(JSON.stringify(bulkLoad));
});

Limited size of FQL output

I am trying to use FQL in order to get the number of comments of all posts on a Facebook page timeline.
I am executing :
https://graph.facebook.com/fql?q=SELECT%20like_info.like_count%20FROM%20stream%20WHERE%20source_id=%22130181453341%22&access_token=CAA...DED
However, this only displays the first posts of the timeline :
{
"data": [
{
"like_info": {
"like_count": 0
}
},
...
{
"like_info": {
"like_count": 16
}
}
]
}
The array stops at some point in the timeline. How to get the full timeline ?
Try adding a where clause that specifies after what date you want comments.

emberdata and mongodb embedded objects ID undefined

I have a problem regarding Ember data and Mongodb embedded objects. Here's my model :
App.Contact = App.Entity.extend({
name : DS.attr('string'),
firstname : DS.attr('string'),
additional_names : DS.attr('string'),
civility : DS.attr('string'),
birthday : DS.attr('date'),
organization : DS.belongsTo('App.Organization'),
role : DS.attr('string'),
photo_source : DS.attr('string'),
photo_uri : DS.attr('string'),
gravatar_mail : DS.attr('string'),
addresses : DS.hasMany('App.Address', { embedded: true }),
emails : DS.hasMany('App.Email', { embedded: true }),
phones : DS.hasMany('App.Phone', { embedded: true })
});
Now I'm fetching a contact through the API: (GET /app/api/v1/contact/4f86c4774ab63c2417000001/) here's what I get :
{
"additional_names": null,
"addresses": [],
"birthday": null,
"civility": null,
"emails": [
{
"email": "alexandre#test.com",
"label": null,
"resource_uri": "/app/api/v1/contact/4f86c4774ab63c2417000001/emails/0/",
"type": "HOME"
}
],
"firstname": "Alexandre",
"gravatar_mail": null,
"groups": [],
"id": "4f86c4774ab63c2417000001",
"name": "Simoui",
"organization": null,
"phones": [],
"photo_source": null,
"photo_uri": "/static/img/nophoto.png",
"resource_uri": "/app/api/v1/contact/4f86c4774ab63c2417000001/",
"role": null
}
My "root" object has an id but the embedded object "emails" hasn't. Because in mongodb, id is not set on subdocuments, but only on root document.
This way ember-data see that "email" object hasn't id and then it try to get the full object through the API. For example : GET /app/api/v1/email/set// 404 (NOT FOUND)
To be sure it was the wright problem I tried to return Mongodb subdocuments with a fake ID field. Like : (see difference on email object)
{
"additional_names": null,
"addresses": [],
"birthday": null,
"civility": null,
"emails": [
{
"id": 431,
"email": "alexandre#test.com",
"label": null,
"resource_uri": "/app/api/v1/contact/4f86c4774ab63c2417000001/emails/0/",
"type": "HOME"
}
],
"firstname": "Alexandre",
"gravatar_mail": null,
"groups": [],
"id": "4f86c4774ab63c2417000001",
"name": "Simoui",
"organization": null,
"phones": [],
"photo_source": null,
"photo_uri": "/static/img/nophoto.png",
"resource_uri": "/app/api/v1/contact/4f86c4774ab63c2417000001/",
"role": null
}
Then I got no problem everything is fine. So my question is: Is there a way to fix it?
I have begun experimenting with a workaround. I only use embedded objects without IDs on a read-only basis, so I haven't tested saving, creation, and proper model state management (isDirty, etc.)...but so far this has solved my similar problem.
Unfortunately I needed to modify the ember-data source. See my fork of ember-data.
The extent of my change involved modifying the hasAssociation() function of DS.hasMany. What I did was inject fake IDs the first time the computed property that accesses the association returns. I keep a client-side ID counter, injectedIdCounter in the closure that defines hasAssociation() as well as a function to fetch an ID and update the counter. I then define a new option, trueEmbedded which is an embedded sub-document with no ID. Each time get() is called on the association, the elements are checked for IDs and if the id doesn't exist one is injected. If IDs have been added, then set() needs to be called so the modified association is stored back on the parent object. This solved my problem at least. Here's my code.
var injectedIdCounter = 1;
var getInjectedId = function() {
return injectedIdCounter++;
};
var hasAssociation = function(type, options) {
options = options || {};
var embedded = options.embedded,
findRecord = embedded ? embeddedFindRecord : referencedFindRecord;
var meta = { type: type, isAssociation: true, options: options, kind: 'hasMany' };
return Ember.computed(function(key, value) {
var data = get(this, 'data'),
store = get(this, 'store'),
ids, id, association;
if (typeof type === 'string') {
type = get(this, type, false) || get(window, type);
}
key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
if (options.trueEmbedded) {
association = get(data, key);
var injectedIdCount = 0;
association.forEach(function(item) {
if (Ember.none(item.id)) {
item.id = getInjectedId();
injectedIdCount++;
}
});
if (injectedIdCount > 0) {
set(data, key, association);
}
ids = embeddedFindRecord(store, type, data, key);
} else {
ids = findRecord(store, type, data, key);
}
association = store.findMany(type, ids || []);
set(association, 'parentRecord', this);
return association;
}).property().cacheable().meta(meta);
};
You would think that an embedded document doesn't need an ID, but the way ember-data first fetches all the IDs of the objects and then the objects themselves, even for an embedded association, means that some messy solution like this is required.
Hopefully this will be fixed in a future release of Ember.
Cheers,
Kevin