Extract nested key from string data structure - ruby

I am using mailgun for sending email. It has api for add “Unsubscribe me” feature. I am using it in my rails app.
Using this command, i get list of all unsubscribed users i.e. entries in unsubscribes table of mailgun.
RestClient.get "https://api:key-3ax6xnjp29jd6fds4gc373sgvjxteol0" "#api.mailgun.net/v2/samples.mailgun.org/unsubscribes"
I am storing its output in #unsubscriber. So my controller has:
#unsubscribers = RestClient.get "https://api:key-3ax6xnjp29jd6fds4gc373sgvjxteol0" "#api.mailgun.net/v2/samples.mailgun.org/unsubscribes"
When i display the output in view, <%= #unsubscribers %> i get string:
{
"total_count": 1,
"items": [{
"created_at": "Sun, 11 Aug 2013 08:07:22 GMT",
"tag": "*",
"id": "sdfsdfw12423535456",
"address": "xyz#abc.com"
}]
}
As I want to delete unsubscribed emails from my database, I want only emails in #unsubscribers. But it contains whole string.
I am not getting how to extract email from above string so that i can have list of emails in #unsubscribers and i can delete them from my app.
Can anybody help me?

If you are trying to access the address of the first subscriber:
#unsubscriber['items'].first['address']
Safer code:
((#unsubscriber['items'] || []).first || {} )['address']
If you are trying to collect all the addresses:
(#unsubscriber['items'] || []).map{|s| ['address']}

#unsubscriber is a hash. items is an array of hashes. You need to get the first item using [0]. Then you need the address value
#unsubscriber["items"][0]["address"]

Related

Data Operation - Select (Json Array)

I have a JSON Array with the following structure:
{
"InvoiceNumber": "11111",
"AccountName": "Hospital",
"items": {
"item": [
{
"Quantity": "48.000000",
"Rate": "0.330667",
"Total": "15.87"
},
{
"Quantity": "1.000000",
"Rate": "25.000000",
"Total": "25.00"
}
]
}
}
I would like to use Data Operation "Select" to select invoice numbers with invoice details.
Select:
From body('Parse_Json')?['invoices']?['invoice']
Key: Invoice Number;Map:item()['InvoiceNumber'] - this line works
Key: Rate; Map: item()['InvoiceNumber']?['items']?['item']?['Rate']- this line doesnt work.
The error message says "Array elements can only be selected using an integer index". Is it possible to select the Invoice Number AND all the invoice details such as rate etc.? Thank you in advance! Also, I am trying not to use "Apply to each"
You have to use a loop in some form, the data resides in a array. The only way you can avoid looping is if you know that the number of items in the array will always be of a certain length.
Without looping, you can't be sure that you've processed each item.
To answer your question though, if you want to select a specific item in an array, as the error describes, you need to provide the index.
This is the sort of expression you need. In this one, I am selecting the item at position 1 (arrays start at 0) ...
body('Parse_JSON')?['items']?['item'][1]['rate']
Using your JSON ...
You can always extract just the items object individually but you'll still need to loop to process each item IF the length is never a static two items (for example).
To extract the items, you select the object from the dynamic content ...
Result ...

How can I filter if any value of an array is contained in another array in rethinkdb/reql?

I want to find any user who is member of a group I can manage (using the webinterface/javascript):
Users:
{
"id": 1
"member_in_groups": ["all", "de-south"]
},
{
"id": 2
"member_in_groups": ["all", "de-north"]
}
I tried:
r.db('mydb').table('users').filter(r.row('member_in_groups').map(function(p) {
return r.expr(['de-south']).contains(p);
}))
but always both users are returned. Which command do I have to use and how can I use an index for this (I read about multi-indexes in https://rethinkdb.com/docs/secondary-indexes/python/#multi-indexes but there only one value is searched for)?
I got the correct answer at the slack channel so posting it here if anyone else comes to this thread through googling:
First create a multi index as described in
https://rethinkdb.com/docs/secondary-indexes/javascript/, e. g.
r.db('<db-name>').table('<table-name>').indexCreate('<some-index-name>', {multi: true}).run()
(you can omit .run() if using the webadmin)
Then query the data with
r.db('<db-name>').table('<table-name>').getAll('de-north', 'de-west', {index:'<some-index-name>'}).distinct()

How to set data in redis hash using ruby

Currently I am caching data from active record to redis by doing following:
redis.rb
$redis = Redis::Namespace.new("bookstore", :redis => Redis.new)
authors_helper.rb
def fetch_authors
authors = $redis.get('authors')
if authors.nil?
authors = Author.all.to_json
$redis.set("authors", authors).to_json
$redis.expire("authors", 5.hour.to_i)
end
JSON.load authors
end
So currently I am using basic set and get to cache and read data from redis.
I want to use hmset instead of just set. The redis way to to this job is as follows:
(Just an example)
HMSET user:1001 name "Mary Jones" password "hidden" email "mjones#example.com"
The authors table in my app consists of following field: id ,name, created_at, updated_at
What is the ruby way to use hmset so that I can cache authors data in a redis hash?
I don't think you can save all authors this way. This is because a hash can store only one value for each key. So name and created_at cannot be keys, because all authors need to store their own values for these keys, but you can use each key only once.
If you're using Ruby on Rails, using Rails.cache is preferred - this way you don't have to worry about the way Rails stores the object in Redis.
However, if you want to use hmset for some reason, I believe the best you can do is something like this:
authors = Author.all.flat_map { |author| [author.id.to_s, author.attributes.to_json] }
$redis.hmset("authors", *authors_data)
The first line will return something like this:
['1', '{"name": "Mary Jones", "email": "m#example.com"}', '2', '{"name": "Another name", "email": "e#example.com"']
hmset command does not accept array, but a flat list of attributes, that's why in the 2nd line you need to pass *authors_data to the function.
Then, internally it will look like this:
{
'1' => '{"name": "Mary Jones", "email": "m#example.com"}',
'2' => '{"name": "Another name", "email": "e#example.com"'
}
Later you can do $redis.hmget("authors", '1') which will return a String '{"name": "Mary Jones", "email": "m#example.com"}'

Facebook Graph API not getting all events, even if 'hosted by'

I am using the FB Graph API and not getting all the events. I know through searching this forum that only events that are 'hosted by' the group come through but I am not event getting all the events 'hosted by' the groups.
For example, I am trying to get the events from https://www.facebook.com/pg/goldenlionbristol/events/. The event on 1st Nov 2017, https://www.facebook.com/events/315066482344970/ is hosted by The Golden Lion but is not coming through. Nether is the one on 2nd November 2017, https://www.facebook.com/events/153007618626727/, which is also hosted by The Golden Lion.
The code (ruby) I am using
Koala.config.api_version = 'v2.10'
oauth = Koala::Facebook::OAuth.new app_id, app_secret
graph = Koala::Facebook::API.new oauth.get_app_access_token
fb_events = graph.get_object( fb_venue["url_listings"] )
For the example above fb_venue["url_listings"] = 'goldenlionbristol/events'. This is working fine for other groups (i.e. https://www.facebook.com/pg/MrWolfs/events/)
Events are not returned in order of which is closest to the current date (which a simple look at the result should have made obvious), and with the default limit of 25, the first event currently simply is on the second page of results.
The second event is actually a repeating event. Just look at the return for that one individually by id:
"start_time": "2017-10-05T21:00:00+0100",
"event_times": [
{
"id": "153007635293392",
"start_time": "2017-11-02T21:00:00+0000",
"end_time": "2017-11-02T23:00:00+0000"
},
{
"id": "153007631960059",
"start_time": "2017-10-05T21:00:00+0100",
"end_time": "2017-10-05T23:00:00+0100"
},
{
"id": "153007628626726",
"start_time": "2017-12-07T21:00:00+0000",
"end_time": "2017-12-07T23:00:00+0000"
}
],
So that has two upcoming "occurrences" on Nov 2nd and Dec 7th. Oh, and it already had one on Oct 5th ... and that one shows up on the second page of results as well.
You will have to get to the repeated occurrences via the "original" event, and have to go back in events until you catch it. In the API reference for the event object there's no mention of repeating events, so it looks like it has not kept up with the evolution of UI features in that regard.

Multiple atomic updates using MongoDB?

I am using Codeigniter and Alex Bilbie's MongoDB library.
In my API that I am developing users can upload images and other users can comment on them.
I have chosen to include the comments as sub documents to the images.
Each comment contains:
Fullname (of author)
Comment
Created_at
So in other words. The users full name is "hard coded" into each comment so if they
later decides to change their names I have a problem.
I read that I can use atomic updates to update all occurrences of the name (like in comments) but how can I do this using Alex´s library? Can I update all places where the name is wrong?
UPDATE
This is how the image document looks like with the comments.
I think that it is pretty strange that MongoDB encourage the use of subdocuments but then does not include a way to update multiple items in an array.
{
"_id": ObjectId("4e9ead773dc793dc01020000"),
"description": "An image",
"category": "accident",
"comments": [
{
"id": ObjectId("4e96bd063dc7937202000000"),
"fullname": "James Bond",
"comment": "This is a comment.",
"created_at": "2011-10-19 13:02:40"
}
],
"created_at": "2011-10-19 12:59:03"
}
Thankful for all help!
I am not familiar with codeignitor, but mb mongodb shell syntax will help you:
db.comments.update( {"Fullname":"Andrew Orsich"},
{ $set : { Fullname: "New name"} }, false, true )
Last true flag indicate that you want update multiple documents. So it is possible to update all comments in one update operation.
BTW: denormalazing (not 'hard coding') data in mongodb and nosql in general is usual operation. Also operation that require update a lot of documents usually work async. But it is up to you.
Update:
db.comments.update( {"comments.Fullname":"Andrew Orsich"},
{ $set : { comments.$.Fullname: "New name"} }, false, true )
But, above query will update full name in first comment on nested array. If you need to affect changes to more than one array element you will need to use multiple update statements.

Resources