MongoDB returns empty array - ruby

I have a MongoDB that spits record onto a webpage
require 'mongo'
require 'json'
connection = Mongo::Connection.new
db = connection.db("salemDB")
db = Mongo::Connection.new.db("salemDB")
newsCollection = db["news"]
require 'sinatra'
set:port, 2222
get '/' do
redirect 'index.html'
end
get "/checkMail" do
newsCollection.find_one({}, {}).to_a.to_json
end
get "/:id" do
newsCollection.find("_id" => params[:id]).to_a.to_json
end
/checkmail outputs this
(formatted for reading pleasure)
[
[
"_id",
{
"$oid":"50880c8564a15e2631000001"
}
],
[
"date",
"2012-10-24T17:42:54+02:00"
],
[
"subject",
"This is a piece of news"
]
]
/50880c8564a15e2631000001 outputs this
[]
Why won't it give my object back?

That's because the id actually is not a string or Integer it's an BSON::ObjectId, so you have to query with one of those.
This should work
newsCollection.find("_id" => BSON::ObjectId(params[:id])).to_a.to_json

Related

Create a nested HASH from a API Call doesn't work properly

I am new here and i hope that I'm doing everything right.
I also searched the Forum and with Googel, but I didn't find the answer. (Or I did not notice that the solution lies before my eyes. Then I'm sorry >.< .)
i have a problem and i dont exactly know what i am doing wrong at the moment.
I make a API request and get a big JSON back. It looks somehow like that:
"apps": [
{
"title": "XX",
... many more data
},
{
"title": "XX",
... many more data
},
{
"title": "XX",
... many more data
}
... and so on
]
After that i want to create a hash with the data i need, for example it should look like:
{
"APP_0" => {"Title"=>"Name1", "ID"=>"1234", "OS"=>"os"}
"APP_1" => {"Title"=>"Name2", "ID"=>"5678", "OS"=>"os"}
}
but the values in the hash that i create with my code looks like:
"APP_1", {"Title"=>"Name2", "ID"=>"5678", "OS"=>"os"}
dont now if this is a valid hash? And after that i want to iterate through the Hash and just output the ID. But I get an error (TypeError). What am i doing wrong?
require 'json'
require 'net/http'
require 'uri'
require 'httparty'
response = HTTParty.get('https://xxx/api/2/app', {
headers: {"X-Toke" => "xyz"},
})
all_apps_parse = JSON.parse(response.body)
all_apps = Hash.new
all_apps_parse["apps"].each_with_index do |app, i|
all_apps["APP_#{i}"] = {'Title' => app["title"],
'ID' => app["id"],
'OS' => app["platform"]}
end
all_apps.each_with_index do |app, i|
app_id = app["App_#{i}"]["id"]
p app_id
end
I hope someone can understand the problem and can help me :-). Thanks in advance.
Assuming the data looks something like this:
all_apps_parse = { "apps" => [
{
"title" => "Name1",
"id" => 1234,
"platform" => "os"
},
{
"title" => "Name2",
"id" => 5678,
"platform" => "os"
},
{
"title" => "Name3",
"id" => 1111,
"platform" => "windows"
}]
}
and with a little idea of what you want to achieve, here is my solution:
all_apps = Hash.new
all_apps_parse["apps"].each_with_index do |app, i|
all_apps["APP_#{i}"] = { 'Title' => app["title"],
'ID' => app["id"],
'OS' => app["platform"] }
end
all_apps
=> {"APP_0"=>{"Title"=>"Name1", "ID"=>1234, "OS"=>"os"}, "APP_1"=>{"Title"=>"Name2", "ID"=>5678, "OS"=>"os"}, "APP_2"=>{"Title"=>"Name3", "ID"=>1111, "OS"=>"windows"}}
all_apps.each do |key, value|
puts key # => e.g. "APP_0"
puts value['ID'] # => e.g. 1234
end
# Prints
APP_0
1234
APP_1
5678
APP_2
1111

Ruby: collect a target key's value into array from nested hash

I have a file like this:
$urls = [
{name:'Venture Capitals',
sites: [
'http://blog.ycombinator.com/posts.atom',
'http://themacro.com/feed.xml',
'http://a16z.com/feed/',
'http://firstround.com/review/feed.xml',
'http://www.kpcb.com/blog.rss',
'https://library.gv.com/feed',
'http://theaccelblog.squarespace.com/blog?format=RSS',
'https://medium.com/feed/accel-insights',
'http://500.co/blog/posts/feed/',
'http://feeds.feedburner.com/upfrontinsights?format=xml',
'http://versionone.vc/feed/',
'http://nextviewventures.com/blog/feed/',
]},
{name:'Companies and Groups',
sites: [
{name:'Product Companies',
sites: [
'https://m.signalvnoise.com/feed',
'http://feeds.feedburner.com/insideintercom',
'http://www.kickstarter.com/blog.atom',
'http://blog.invisionapp.com/feed/',
'http://feeds.feedburner.com/bufferapp',
'https://open.buffer.com/feed/',
'https://blog.asana.com/feed/',
'http://blog.drift.com/rss.xml',
'https://www.groovehq.com/blog/feed',]},
{name:'Consulting Groups, Studios',
sites: [
'http://svpg.com/articles/rss',
'http://www.thoughtworks.com/rss/insights.xml',
'http://zurb.com/blog/rss',]},
{name:'Communities',
sites: [
'http://alistapart.com/main/feed',
'https://www.mindtheproduct.com/feed/',]},
]},
]
I have organized the $url into different groups. Now I want to extract all the urls out (the link in the sites), how should I do?
The main problem is that, there are sites within sites, as the file showed above.
My problems are:
Am I using a proper file structure to save these links? (array within array). If not, what would be good way to save and group them?
How can I extract all the urls out into a flattened array? so I can later iterate through the list.
I can do this pretty manually, like the code shown below.
sites = []
$urls.each do |item|
item[:sites].each do |sub_item|
if sub_item.is_a?(Hash)
sites.concat sub_item[:sites]
else
sites.append sub_item
end
end
end
File.open('lib/flatten_sites.yaml', 'w') { |fo| fo.puts sites.to_yaml }
But I just feel this is bad code.
An alternative in this specific case, is to collect all the sites attribute, but I feel this is also very constrained, and may not help in some other cases.
If you have Hash, you can use this recursive method
Input
urls = [
{
:name => 'Venture Capitals',
:sites => [
'http://blog.ycombinator.com/posts.atom',
'http://themacro.com/feed.xml',
'http://a16z.com/feed/',
'http://firstround.com/review/feed.xml',
'http://www.kpcb.com/blog.rss',
'https://library.gv.com/feed',
'http://theaccelblog.squarespace.com/blog?format=RSS',
'https://medium.com/feed/accel-insights',
'http://500.co/blog/posts/feed/',
'http://feeds.feedburner.com/upfrontinsights?format=xml',
'http://versionone.vc/feed/',
'http://nextviewventures.com/blog/feed/',
]
},
{
:name => 'Companies and Groups',
:sites => [
{
:name => 'Product Companies',
:sites => [
'https://m.signalvnoise.com/feed',
'http://feeds.feedburner.com/insideintercom',
'http://www.kickstarter.com/blog.atom',
'http://blog.invisionapp.com/feed/',
'http://feeds.feedburner.com/bufferapp',
'https://open.buffer.com/feed/',
'https://blog.asana.com/feed/',
'http://blog.drift.com/rss.xml',
'https://www.groovehq.com/blog/feed',]
},
{
:name => 'Consulting Groups, Studios',
:sites => [
'http://svpg.com/articles/rss',
'http://www.thoughtworks.com/rss/insights.xml',
'http://zurb.com/blog/rss',]
},
{
:name => 'Communities',
:sites => [
'http://alistapart.com/main/feed',
'https://www.mindtheproduct.com/feed/',]
}
]
}
]
Method
def get_all_sites(data)
data[:sites].map { |r| Hash === r ? get_all_sites(r) : r }
end
urls.map { |r| get_all_sites(r) }.flatten
Output
[
"http://blog.ycombinator.com/posts.atom",
"http://themacro.com/feed.xml",
"http://a16z.com/feed/",
"http://firstround.com/review/feed.xml",
"http://www.kpcb.com/blog.rss",
"https://library.gv.com/feed",
"http://theaccelblog.squarespace.com/blog?format=RSS",
"https://medium.com/feed/accel-insights",
"http://500.co/blog/posts/feed/",
"http://feeds.feedburner.com/upfrontinsights?format=xml",
"http://versionone.vc/feed/",
"http://nextviewventures.com/blog/feed/",
"https://m.signalvnoise.com/feed",
"http://feeds.feedburner.com/insideintercom",
"http://www.kickstarter.com/blog.atom",
"http://blog.invisionapp.com/feed/",
"http://feeds.feedburner.com/bufferapp",
"https://open.buffer.com/feed/",
"https://blog.asana.com/feed/",
"http://blog.drift.com/rss.xml",
"https://www.groovehq.com/blog/feed",
"http://svpg.com/articles/rss",
"http://www.thoughtworks.com/rss/insights.xml",
"http://zurb.com/blog/rss",
"http://alistapart.com/main/feed",
"https://www.mindtheproduct.com/feed/"
]
I hope this helps
The solution similar to what Lukas Baliak proposed, but using more suitable Proc instead of redundant method (works for any amount of level’s nesting):
deep_map = ->(data) do
data[:sites].flat_map { |r| r.is_a?(String) ? r : deep_map.(r) }
end
urls.flat_map(&deep_map)

How to specify type of JSON value?

I'm using Grape on Padrino to make a test API for my mobile app.
How can I specify the type of my JSON object?
Here is how i do it, but every returned value is a String:
module Acme
module Api
class Ping < Grape::API
format :json
get '/user/112132a08s245c/availability_list' do
{
"availability_list"=> [
{
:type=> "OOO",
:from_date=> "21-12-2004",
:to_date=> "21-23-2007",
:all_day=> "false"
},
{
:type=> "WFH",
:from_date=> "21-12-2004",
:to_date=> "21-23-2007",
:all_day=> "false"
}
]
}
end
get '/user/112132a08s245c/issues' do
{
"issues"=> [
{
:issure_id=> "1ab300co221",
:title=> "No water",
:description=> "No water in kitchen",
:severity=> "low",
"location" => {
:lat => "37.4224764",
:lng => "-122.0842499"
}
},
{
:issure_id=> "1ab300co222",
:title=> "No fire",
:description=> "No fire in kitchen",
:severity=> "low",
"location" => {
:lat => "37.4224764",
:lng => "-122.0842499"
}
}
]
}
end
end
end
Meditate on this:
require 'json'
foo = {'a' => 1}
foo.class # => Hash
str = JSON[foo] # => "{\"a\":1}"
str.class # => String
bar = JSON[str] # => {"a"=>1}
bar.class # => Hash
You need to read the JSON spec. JSON serializes data into a string because objects can't be transferred between disparate languages. When it sees an object the parser serializes it into a string. When the incoming string is received and passed on to the parser, it knows it has to convert the string back to an object.

Saving Point to a Google Fitness API (fitness.body.write)

Im trying to save a Point with float value into fitness.body.
Getting value is not a problem, while saving a new point causes 403. No permission to modify data for this source.
Im using DataSetId derived:com.google.weight:com.google.android.gms:merge_weight to find point and read value, and raw:com.google.weight:com.google.android.apps.fitness:user_input to insert data.
.
Here is a workflow using Ruby and google-api-ruby-client:
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'pry'
# Initialize the client.
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
fitness = client.discovered_api('fitness')
# Load client secrets from your client_secrets.json.
client_secrets = Google::APIClient::ClientSecrets.load
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/fitness.body.write',
'https://www.googleapis.com/auth/fitness.activity.write',
'https://www.googleapis.com/auth/fitness.location.write']
)
client.authorization = flow.authorize
Forming my new data Point:
dataSourceId = 'raw:com.google.weight:com.google.android.apps.fitness:user_input'
startTime = (Time.now-1).to_i # 1 Second ago
endTime = (Time.now).to_i
metadata = {
dataSourceId: dataSourceId,
maxEndTimeNs: "#{startTime}000000000", # Faking nanoseconds with tailing zeros
minStartTimeNs: "#{endTime}000000000",
point: [
{
endTimeNanos: "#{endTime}000000000",
startTimeNanos: "#{startTime}000000000",
value: [
{ fpVal: 80 }
]
}
]
}
Attempting to save the point:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)
And as I indicated previously im getting 403. No permission to modify data for this source
#<Google::APIClient::Schema::Fitness::V1::Dataset:0x3fe78c258f60 DATA:{"error"=>{"er
rors"=>[{"domain"=>"global", "reason"=>"forbidden", "message"=>"No permission to modif
y data for this source."}], "code"=>403, "message"=>"No permission to modify data for
this source."}}>
I believe, I selected all required permissions in the scope. I tried submitting the point to both accessible datasetid's for fitness.body.
Please let me know if im doing anything wrong here.
Thank you!
I encountered the same situation, turns out you can NOT insert data points directly into the datasource "raw:com.google.weight:com.google.android.apps.fitness:user_input". From the name, one might guess out this datasource is reserved. So the workaround is to add your own datasource, note should with dataType.name="com.google.weight", like this:
{
"dataStreamName": "xxxx.body.weight",
"dataType": {
"field": [
{
"name": "weight",
"format": "floatPoint"
}
],
"name": "com.google.weight"
},
"dataQualityStandard": [],
"application": {
"version": "1",
"name": "Foo Example App",
"detailsUrl": "http://example.com"
},
"device": {
"model": "xxxmodel",
"version": "1",
"type": "scale",
"uid": "xxx#yyy",
"manufacturer": "xxxxManufacturer"
},
"type": "derived"
}
then after the successful creation, you can use this datasource(datastream id) to insert your own data points, and then the inserted data points will also be included in the datasource "derived:com.google.weight:com.google.android.gms:merge_weight" when you do the querying with suffix "dataPointChanges".
Try adding an Authorization header:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:headers => {'Authorization' => 'Bearer YOUR_AUTH_TOKEN'},
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)

How can I access an array of objects from GData JSON in Ruby?

I am trying to write a Jekyll extension that will embed comments from a Blogger blog.
I am able to fetch the comments feed as JSON, and process it enough to pull out the total number of comments. However, I have not figured out how to process each comment in the feed.
json_url = "http://www.blogger.com/feeds/8505008/593465383646513269/comments/default/?alt=json"
json_rep = Net::HTTP.get_response(json_url)
json_rep = JSON.parse(json_rep.body)
json_rep['feed']['openSearch$totalResults']['$t'] # => "4"
json_rep['feed']['entry'].class # => Array
json_rep['feed']['entry'].length
# => Liquid Exception: undefined method `length' for nil:NilClass in post
This is my first time writing any code in Ruby. What am I doing wrong?
Here are the relevant parts of the JSON I am trying to parse.
{
"feed": {
"openSearch$totalResults": {
"$t": "4"
},
"entry": [
{
"id": {
"$t": "tag:blogger.com,1999:blog-8505008.post-491866073982779922"
},
"published": {
"$t": "2013-01-08T15:23:47.322-04:00"
},
"content": {
"type": "html",
"$t": "Recently, my sister has updated it more than I have. \u00dcber-fail on my part. :p"
}
}
]
}
}
This is what you should look at doing:
require 'rubygems'
require 'json'
require 'net/http'
require 'net/https'
require 'uri'
url = "http://www.blogger.com/feeds/8505008/593465383646513269/comments/default/?alt=json"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
json_rep = JSON.parse(response.body)
puts json_rep['feed']['openSearch$totalResults']['$t']
entries = json_rep['feed']['entry']
entries.each do |entry|
puts entry["id"]["$t"]
#add what ever code you like here
end
This outputs:
4
tag:blogger.com,1999:blog-8505008.post-491866073982779922
tag:blogger.com,1999:blog-8505008.post-4792479891671746788
tag:blogger.com,1999:blog-8505008.post-4766604955439002209
tag:blogger.com,1999:blog-8505008.post-5484003770204916000

Resources