How to sort an array of mongoid documents (array contains different mongoid document types)? - ruby

I have two arrays of Mongoid documents, FirstType documents and SecondType documents. Both are embedded in User.
user.first_types = [#<FirstType _id: 51a10b4883c336ebef0002a8, created_at: 2013-05-25 19:04:40 UTC, updated_at: 2013-05-25 19:04:40 UTC, datetime: 2013-03-28 15:03:22 UTC, text: "Hello 1">]
user.second_types = [#<SecondType _id: 51a6058783c3368a62000003, created_at: 2013-05-29 13:41:27 UTC, updated_at: 2013-05-29 13:41:27 UTC, datetime: 2013-05-29 08:23:27 UTC, text: "Hello 2">]
Then I merge them with this line of code:
all_types = user.first_types+user.second_types
I now wish to sort the all_types array by the attribute datetime (newest datetime first, so the SecondType object should be the first one).
I have tried the conventional Mongoid and Ruby array methods, but they don't seem to work when I mix up Mongoid documents. Any ideas?

Use Enumerable#sort_by and negate the numeric value of the "datetime" attribute for descending order:
all_types.sort_by { |x| -x.datetime.to_f }

Related

Is there a way to create a runtime field in Elasticsearch that is equal to a 'Value'/'Sum of Value across index'?

I have a task to show the percent of value a set of filtered documents represents vs the entire value represented across a whole year. For example:
[{
name: 'Foo',
value: 12,
year: 2021
},
{
name: 'Bar',
value: 2,
year: 2021
},
{
name: 'Car',
value: 10,
year: 2021
},
{
name: 'Lar',
value: 4,
year: 2022
}]
I'd like to create a runtime field that would equal .5 for 'Foo' (12/(12+2+10)), .42 for 'Car' (10/(12+2+10)) and 1 for 'Lar' (4/4). Is this possible? Is there a better way to achieve this result? The ultimate goal is that if someone creates a query that returns 'Foo' and 'Car' they could sum the runtime field to get .92 (.5+.42) and that such a result could be used in a Kibana Lens visualization.
I've tried creating queries that return the above results, and that is easy enough, but those queries aren't usable inside Kibana which also has global filters to account for. That's why I thought a calculated field that represents the ratio of a document's value in relation to the sum of all documents' values would be useful.

scaled_float being presented as string

I have several indexes of type scaled_float. The problem is that when I realize a search, those indexes are presented as string instead of numeral.
on my elasticsearch document model I have the following:
indexes :price, type: 'float', index: false
and when I get to search, the result comes this way:
...,
"price": "89.00"
but I wanted to be
"price": 89.00
Is it possible?

Counting documents by property occurrence in Kibana

I'm trying to create a visualization that looks like this:
Foobar, 10
Bar, 8
Baz, 5.6
The first column is the aggregation itself. Imagine i have documents like this:
{
id: 1,
name: 'lorem ipsum',
type: 'A'
author: {
name: 'Foobar',
}
}
{
id: 2,
name: 'dolor sit amet',
type: 'B',
author: {
name: 'Foobar',
}
}
So, i want to add a +1 to the score of "Foobar" everytime i find a document of type A. And a +2 to the score if i find a document of type B. Basically, aggregating by the author name, and calculating a dynamic value on results.
Is this possible in Kibana? Thanks for the help.
AFAIK, you can't do this in Kibana in visualize panel, maybe you can try it in program then index the result into es.

How to check for value in an array without iteration

I want a single line of ruby (not using each) that will answer this question: Is there a follower_id of 2397558816 in this array?
myArray = [ #<Follower id: 1, username: "Prep Bootstrap", imageurl: "http://pbs.twimg.com//profile_images/2825468445/2a4...", user_id: "thefonso", follower_id: "2397558816", created_at: "2014-05-21 15:29:03", updated_at: "2014-05-21 15:29:03">, #<Follower id: 2, username: "JAVA Developer", imageurl: "http://pbs.twimg.com//profile_images/2825468445/2a4...", user_id: "thefonso", follower_id: "2352382640", created_at: "2014-05-21 15:29:05", updated_at: "2014-05-21 15:29:05"> ]
I am convinced that there must be a ruby method or combo of such that can do this. Can this be done?
You were on the right way: use Enumerable#any?:
myarray.any? { |v| v.follower_id == 2397558816 }
Note: This answer is based on assumption it is an ActiveRecord relation. If it is not, please comment and I'll remove this answer.
This is not a simple array, it is ActiveRecord::Relation object, which is a wrapper around an array. You should almost never use pure array objects on it, as this class is responsible for fetching objects from database. Using any? will fetch all the records from db and then iterate over it searching for match. Instead you should check it on a db lavel to limit number of fetched records (performance):
relation.exists?(follower_id: 2397558816)
(myArray.select {|elem| elem.instance_variable_get(:#id) == 1234567}) != []
Returns true if the array contains an element with the given id, and false if not

How do you calculate the average of a all entries in a field from a specific collection in Mongo using Ruby

Given the following data:
{
_id: ObjectId("51659dc99d62eedc1a000001"),
type: "image_search",
branch: "qa_media_discovery_feelobot",
time_elapsed: 19000,
test: "1365613930 All Media",
search_term: null,
env: "delta",
date: ISODate("2013-04-10T17:13:45.751Z")
}
I would like to run a command like:
avg_image_search_time = #coll.find("type" => "image_search").avg(:time_elapsed)
How would I accomplish this?
I understand the documentation on this is kind of difficult to follow.
avg_image_search_time = #coll.aggregate([ {"$group" => {"_id"=>"$type", "avg"=> {"$avg"=>"$time_elapsed"}}}, {"$match" => {"_id"=>"image_search"}} ]).first['avg']
To break this down:
We are grouping the matches by the type field, and returning the $avg time_elapsed for each type. We name the resulting average avg. Then, of those groups, filter out only the ones where the group _id matches image_search. Finally, since aggregate always returns an array, get the first result (there should only be one), and grab the avg field that we named.
Use the mongodb aggregation framework http://docs.mongodb.org/manual/core/aggregation/

Resources