FQL: Trouble joining tables where id is in format USERID_LINKID - facebook-graph-api

I am running the following FQL via the php sdk:
{
"posts" : "SELECT post_id, actor_id, message, type FROM stream WHERE type = '80' AND message != '' AND filter_key in (SELECT filter_key FROM stream_filter WHERE uid='588853265' AND type='newsfeed') AND is_hidden = 0 ORDER BY created_time DESC LIMIT 50",
"actors" : "SELECT uid,name FROM user WHERE uid IN (SELECT actor_id FROM #posts)",
"links" : "SELECT owner, url FROM link WHERE link_id IN (SELECT post_id FROM #posts)"
}
I get results as expected for posts and for actors but not for links (results are empty). I believe the problem is that the link table uses a normal ID but my 'posts' from 'stream' show the ID in the format: USERID_LINKID.
I have played around with substr() and strlen() to get it to work with no luck.

There doesn't seem to be a way to get a link_id from a stream post. Your query is getting the id of the post, but not the link.
However, I don't think you need it. Get rid of the #links sub-query and add attachment to the SELECT statement in your #posts sub-query. You can get the link url at attachment->media->url.
One other critique: You might want to add additional sub-queries for #actors. The actor_id returned by the stream table can be a user, page, or group. Your FQL only resolves users. You'll end up with unknown IDs for links posted by groups and pages.

Related

Oracle Apex 22.21 - Chart Page - Bar Type - Datepicker - How to update the source query to include a count and group by day

This question is a follow up to another SO question
I want a bar chart to show the amount of orders in a given date or range. Koen's updated answer shows:
'The "Value" is the amount of orders on each day. Update your source query to include a count of the orders and group by day. Then make your value attribute the column that has the count.'
How would I go about doing this?
Summary: I have a table ORDERS which contains column ORDER_DATE. I have created a Chart as a Bar type. I want the chart to show the amount of orders in a given date or range.
I'm following this Youtube tutorial which shows how to create a datepicker that returns a range in a Report. I'm trying to replicate this in a chart.
What I've done so far
Created datepicker items P5_DATE_FROM and P5_DATE_TO
Changed the Series Source Type to SQL Query
select ORDER_ID,
ORDER_NUMBER,
ORDER_DATE,
STORE_ID,
FULL_NAME,
EMAIL,
CITY,
STATE,
ZIP_CODE,
CREDIT_CARD,
ORDER_ITEMS,
APEX$SYNC_STEP_STATIC_ID,
APEX$ROW_SYNC_TIMESTAMP
from ORDERS_LOCAL
where ORDER_DATE between TO_DATE(:P5_DATE_FROM,'YYYY-MM-DD') and TO_DATE(:P5_DATE_TO,'YYYY-MM-DD')
Source Page Items to Submit added P5_DATE_FROM,P5_DATE_TO
I basically followed the exact steps of the video.
However, on the Page Designer I cannot save and run page until I select Column Mapping - Label and Value. I've set the Label as ORDER_DATE but I am unsure of what to select for the Value.
Setting the Value to ORDER_DATE shows an error Ajax call returned server error ORA-01403: no data found for CHART Count Orders by Date.
and selecting any other Value such as ORDER_NUMBER or ZIP_CODE populates the chart with the actual integer value of the column (ex: ZIP_CODE returns a chart of x-axis: date, y-axis: actual zip code numbers)
-----------UPDATE----------
Per Koen's answer, I've updated the Source SQL Query to below but I am now receiving an error.
And if I copy the exact query that Koen suggested, I run into below:
I did some messing around and found if I include APEX$SYNC_STEP_STATIC_ID and APEX$ROW_SYNC_TIMESTAMP the missing expression error goes away but instead I receive the GROUP BY error.
Something like this (untested) should work. Use TRUNC to ensure all orders on the same date are grouped (since date has a time portion, you'd have a different column for each different date time. Use ORDER_DATE as label and ORDER_COUNT as value.
select COUNT(ORDER_ID) AS ORDER_COUNT,
TRUNC(ORDER_DATE) AS ORDER_DATE,
from ORDERS_LOCAL
where ORDER_DATE between TO_DATE(:P5_DATE_FROM,'YYYY-MM-DD') and TO_DATE(:P5_DATE_TO,'YYYY-MM-DD')
GROUP BY TRUNC(ORDER_DATE)

Get all friends' ids who liked a post

I am using Facebook FQL to query stream table. I want to get the list of all user ids of friends who liked one of my post. Here is my query:
select post_id,likes.friends, likes.count from stream where source_id = me() and likes.count > 0 limit 200"
However, I only get maximum 4 friend ids in return, even if likes.count > 4, which is exactly like likes.sample.
Is this a bug, or a limitation of FQL? If I can't get full list of Likers here, which table I should look at? If this is not feasible with FQL, how can I make a similar query in Graph API?
Thank you.
Use a multi-query on the stream and like tables
{"posts": "select post_id, likes.count from stream where source_id = me() and likes.count > 0 limit 200",
"friends_who_like_posts":"select user_id FROM like WHERE post_id IN (SELECT post_id FROM #posts) AND user_id IN (SELECT uid2 FROM friend WHERE uid1 = me() )"
}

How to use subquery in django?

I want to get a list of the latest purchase of each customer, sorted by the date.
The following query does what I want except for the date:
(Purchase.objects
.all()
.distinct('customer')
.order_by('customer', '-date'))
It produces a query like:
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
I am forced to use customer_id as the first ORDER BY expression because of DISTINCT ON.
I want to sort by the date, so what the query I really need should look like this:
SELECT * FROM (
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
)
AS result
ORDER BY date DESC;
I don't want to sort using python because I still got to page limit the query. There can be tens of thousands of rows in the database.
In fact it is currently sorted by in python now and is causing very long page load times, so that's why I'm trying to fix this.
Basically I want something like this https://stackoverflow.com/a/9796104/242969. Is it possible to express it with django querysets instead of writing raw SQL?
The actual models and methods are several pages long, but here is the set of models required for the queryset above.
class Customer(models.Model):
user = models.OneToOneField(User)
class Purchase(models.Model):
customer = models.ForeignKey(Customer)
date = models.DateField(auto_now_add=True)
item = models.CharField(max_length=255)
If I have data like:
Customer A -
Purchase(item=Chair, date=January),
Purchase(item=Table, date=February)
Customer B -
Purchase(item=Speakers, date=January),
Purchase(item=Monitor, date=May)
Customer C -
Purchase(item=Laptop, date=March),
Purchase(item=Printer, date=April)
I want to be able to extract the following:
Purchase(item=Monitor, date=May)
Purchase(item=Printer, date=April)
Purchase(item=Table, date=February)
There is at most one purchase in the list per customer. The purchase is each customer's latest. It is sorted by latest date.
This query will be able to extract that:
SELECT * FROM (
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
)
AS result
ORDER BY date DESC;
I'm trying to find a way not to have to use raw SQL to achieve this result.
This may not be exactly what you're looking for, but it might get you closer. Take a look at Django's annotate.
Here is an example of something that may help:
from django.db.models import Max
Customer.objects.all().annotate(most_recent_purchase=Max('purchase__date'))
This will give you a list of your customer models each one of which will have a new attribute called "most_recent_purchase" and will contain the date on which they made their last purchase. The sql produced looks like this:
SELECT "demo_customer"."id",
"demo_customer"."user_id",
MAX("demo_purchase"."date") AS "most_recent_purchase"
FROM "demo_customer"
LEFT OUTER JOIN "demo_purchase" ON ("demo_customer"."id" = "demo_purchase"."customer_id")
GROUP BY "demo_customer"."id",
"demo_customer"."user_id"
Another option, would be adding a property to your customer model that would look something like this:
#property
def latest_purchase(self):
return self.purchase_set.order_by('-date')[0]
You would obviously need to handle the case where there aren't any purchases in this property, and this would potentially not perform very well (since you would be running one query for each customer to get their latest purchase).
I've used both of these techniques in the past and they've both worked fine in different situations. I hope this helps. Best of luck!
Whenever there is a difficult query to write using Django ORM, I first try the query in psql(or whatever client you use). The SQL that you want is not this:
SELECT * FROM (
SELECT DISTINCT ON
"shop_purchase.customer_id" "shop_purchase.id" "shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC, "shop_purchase.date" DESC;
) AS result
ORDER BY date DESC;
In the above SQL, the inner SQL is looking for distinct on a combination of (customer_id, id, and date) and since id will be unique for all, you will get all records from the table. I am assuming id is the primary key as per convention.
If you need to find the last purchase of every customer, you need to do something like:
SELECT "shop_purchase.customer_id", max("shop_purchase.date")
FROM shop_purchase
GROUP BY 1
But the problem with the above query is that it will give you only the customer name and date. Using that will not help you in finding the records when you use these results in a subquery.
To use IN you need a list of unique parameters to identify a record, e.g., id
If in your records id is a serial key, then you can leverage the fact that the latest date will be the maximum id as well. So your SQL becomes:
SELECT max("shop_purchase.id")
FROM shop_purchase
GROUP BY "shop_purchase.customer_id";
Note that I kept only one field (id) in the selected clause to use it in a subquery using IN.
The complete SQL will now be:
SELECT *
FROM shop_customer
WHERE "shop_customer.id" IN
(SELECT max("shop_purchase.id")
FROM shop_purchase
GROUP BY "shop_purchase.customer_id");
and using the Django ORM it looks like:
(Purchase.objects.filter(
id__in=Purchase.objects
.values('customer_id')
.annotate(latest=Max('id'))
.values_list('latest', flat=True)))
Hope it helps!
I have a similar situation and this is how I'm planning to go about it:
query = Purchase.objects.distinct('customer').order_by('customer').query
query = 'SELECT * FROM ({}) AS result ORDER BY sent DESC'.format(query)
return Purchase.objects.raw(query)
Upside it gives me the query I want. Downside is that it is raw query and I can't append any other queryset filters.
This is my approach if I need some subset of data (N items) along with the Django query. This is example using PostgreSQL and handy json_build_object() function (Postgres 9.4+), but same way you can use other aggregate function in other database system. For older PostgreSQL versions you can use combination of array_agg() and array_to_string() functions.
Imagine you have Article and Comment models and along with every article in the list you want to select 3 recent comments (change LIMIT 3 to adjust size of subset or ORDER BY c.id DESC to change sorting of subset).
qs = Article.objects.all()
qs = qs.extra(select = {
'recent_comments': """
SELECT
json_build_object('comments',
array_agg(
json_build_object('id', id, 'user_id', user_id, 'body', body)
)
)
FROM (
SELECT
c.id,
c.user_id,
c.body
FROM app_comment c
WHERE c.article_id = app_article.id
ORDER BY c.id DESC
LIMIT 3
) sub
"""
})
for article in qs:
print(article.recent_comments)
# Output:
# {u'comments': [{u'user_id': 1, u'id': 3, u'body': u'foo'}, {u'user_id': 1, u'id': 2, u'body': u'bar'}, {u'user_id': 1, u'id': 1, u'body': u'joe'}]}
# ....

Get right FQL query with location_post table

I am trying to get all posts near specific location. I post some statuces and photos on my FB page with location.
In Graph API Explorer I run this query:
SELECT id, coords, type, page_id, timestamp FROM location_post WHERE author_uid = me()
and it results in right way, but when I add:
SELECT id, coords, type, page_id, timestamp FROM location_post WHERE author_uid = me() AND distance(latitude, longitude, '47', '122') < 10000
then all results cleared.
I tried to get distance in query and it results in nice numbers like 33 or 454. So why distance function in WHERE section results in nothing?
Also request from example:
SELECT id, page_id
FROM location_post
WHERE distance(latitude, longitude, '37.86564', '-122.25061') < 10000
does't show anything.
For the example query, Your lat/long is reported somewhere outside of Oakland, CA. To return data you need one of the following:
If you requested user_location permission in your access token, you need to have made or been tagged in a post made within 10km (~6.25 mi) of this point.
If you requested friends_location permission in your access token, a friend of yours needs to have made this post.

How to write FQL to fetch news feeds

I have to fetch all data which is on News Feeds (public wall). What query should I write ?
I wrote "SELECT likes,message FROM stream WHERE source_id = %lld limit 50 " query but it is returning my wall value. I want to fetch all data which is on my wall as well as on public (News Feed).
Thanks in advance
You need to use the filter_key to select the type of feed to use. The type you are after would probably be newsfeed, so the query could be something like this:
SELECT post_id, actor_id, target_id, message FROM stream WHERE filter_key in (SELECT filter_key FROM stream_filter WHERE uid = me() AND type = 'newsfeed')
For more information, have a look at the stream_filter docs.
How about doing it without querying FQL? :)
Use the Graph API instead:
https://graph.facebook.com/me/home?access_token=...
Try it on using "Graph API Explorer". /me/home