How to fetch a document by its ID in elasticsearch rails - elasticsearch

I see in the elasticsearch docs you can fetch a document by its ID. Is there any equivalent in elasticsearch rails? I'm feeding by API with "as_indexed_json" and it's a somewhat expensive query, I'd like to return ths JSON straight out of elasticsearch in my API.

You can fetch a particular document from a given index by id with the get method on Elasticsearch::Transport::Client. The get method expects a single hash argument with keys for the index you want to fetch from and the id of the document you want to fetch.
So, all together you need 3 things:
A client object
The name of the index
The id of the document (i.e. your model id)
client = YourModel.__elasticsearch__.client
document = client.get({ index: YourModel.index_name, id: id_to_find })

Here how you can accomplish it.
This is from controller action and works well for me.
def show
client = Elasticsearch::Client.new host:'127.0.0.1:9200', log: true
response = client.search index: 'example', body: {query: { match: {_id: params[:id]} } }
#example = response['hits']['hits'][0]['_source']
respond_to do |format|
format.html # show.html.erb
format.js # show.js.erb
format.json { render json: #example }
end
#records = Example.search(#example['name']).per(12).results
end

Related

Reading a JSON object in Ruby on Rails

I'm a Ruby on Rails beginner and I'm trying to convert a static website I've made into Rails app where I can store customers and quote data. I'm trying to do this as a RESTful API where my site sends a JSON object containing the customer's information. I check to see if the email in the JSON object matches any of the emails I have in my database and if it does I send back the id of that customer. If not then I create a new customer and send back that id. The problem I'm having is that no matter how I write it, my rails app is not reading the JSON data, so if I have nothing in my database it creates a customer with all null attributes and when I run it again it goes "Oh, I have customer with a null email" and returns that customer.
{
"fname": "William",
"lname": "Shakespeare",
"email": "wshakespeare#test.com",
"bname": "MyCompany",
"primary": "555-555-5555",
"secondary": ""
}
Here's an example of my JSON object.
Here's how my controller is looking:
class CustomersController < ApplicationController
skip_before_action :verify_authenticity_token
wrap_parameters format: [:json, :xml, :url_encoded_form, :multipart_form]
def create
#query = Customer.where(:email === params[:email])
if #query.empty? == true
redirect_to action: "new", status: 301
else
#theid = #query.first.id
render json: {status: 'SUCCESS', message: 'Existing customer', theid:#theid}
end
end
def new
Customer.create(fname: params[:fname], lname: params[:lname], email: params[:email], bname: params[:bname], primary: params[:primary], secondary: params[:secondary])
render json: {status: 'SUCCESS', message: 'New customer', theid: Customer.last.id}
end
Any help would be greatly appreciated. Thanks.

ActiveModel serializer ignores root key when posts or post is empty or nil

I am using active model serializer V0.10.0 with Rails 5 api only application. During implementation I noticed the AMS is completely ignoring the root key when the posts/post is empty or nil respectively. This behavior actually breaks my mobile app as it always expects root key data in all response.
So what I want to achieve here is no matter what I always want data as root element of my Rails app response for all requests.
Response for SHOW API when the post is empty
SHOW render json: #post, root: 'data'
Expected
{
"data": {}
}
Actual
null
Response for INDEX API when the posts are empty
INDEX render json: #posts, root: 'data'
Expected
{
"data": []
}
Actual
{
"posts": []
}
class ApplicationSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
ActiveModelSerializers.config.adapter = :json
def host
Rails.application.secrets.dig(:host_url)
end
end
class PostSerializer < ApplicationSerializer
attributes :id
has_many :comments
end

How to get json response in rails api

I want to display all programmes which I got from a query as json response. I'm getting the programmes, but don't know how to render them through json. I'm using the jbuilder gem and created a create.json.buider.rb file. In my query I'm getting everything correctly, but I'm not receiving a JSON response with whatever details in I have in the query.
This is my controller. I have tried it like this but I'm not getting a json response. Only a status as 200.
class Api::V1::Categories::ProgrammesController < ApiController
respond_to :json
def category
#category=Category.all
#programmes=Programme.joins(:category).find_by(category_id: params[:category_id])
if #programmes.present?
render :json=> {:message=>"Programme not exists "}, :status=>422
else
render :json => #programmes
end
end
end
My create.json.jbuilder file:
json.programmes #programmes
I think you should change #programmes to { :programmers => #programmes.as_json }
class Api::V1::Categories::ProgrammesController < ApiController
def category
#category = Category.all
#programmes = Programme.joins(:category).find_by(category_id: params[:category_id])
if #programmes.present?
render :json=> {:message=>"Programme not exists "}, :status=>422
else
render :json => { :programmers => #programmes.as_json }
end
end
end

How to do POST request to Grape REST API using params block compatible with Swagger

I am using grape to build a REST API, I am having some trouble with params options.
This is how I do a POST request:
# Curl Request
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"title":"hello","body":"world"}'
# {"error":"article is missing"}
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"article":{title":"hello","body":"world"}}'
# {"error":"article is invalid"}
As you can see if I omit article it fails article missing, If i put article and it fails article invalid.
This is the code, I am using grape-entity.
# Entity
module API
module Entities
class Article < Grape::Entity
expose :title, documentation: { type: 'string', desc: 'Title' }
expose :body, documentation: { type: 'string', desc: 'Body' }
end
end
end
# API
desc "Create an article"
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
post '/articles' do
puts params
article = Article.create(params(:title, :body))
represent(article, env)
end
# Add Swagger Docs
add_swagger_documentation mount_path: 'api/doc',
api_version: 'v1',
markdown: GrapeSwagger::Markdown::KramdownAdapter,
hide_documentation_path: true,
base_path: Application.config.base_path,
models: [API::Entities::Article]
Specifically the problem is caused by params block, it requires an :article of type API:Entities::Article.
Also note that, I am using add-swagger-documentation, and this code
produces correct swagger documentation, so the solution have to be
fully compatible with swagger. What is the correct usage of params
block without offending the swagger.
I'm not sure what you're trying to accomplish here. I guess you want to change your post method in a way that it accepts a JSON like this:
{ attribute1: value, attribute2: value }
instead of
{ article: { attribute1: value, attribute2: value } }
In this case, you have to change your params block to something like this
params do
requires :attribute1, type: String, documentation: { eg: "aklsdfj" }
requires :attribute2, type: String, documentation: { eg: "aklsdfj" }
end
instead of
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
The params block above is expecting a JSON containing an article attribute composed by every attribute defined in the entity API::Entities::Article.
In fact, Grape doesn't accept entity objects as a type for a parameter.

tire terms filter not working

I'm trying to achieve a "scope-like" function with tire/elasticsearch. Why is this not working, even when i have entries with status "Test1" or "Test2"? The results are always empty.
collection = #model.search(:page => page, :per_page => per_page) do |s|
s.query {all}
s.filter :terms, :status => ["Test1", "Test2"]
s.sort {by :"#{column}", "#{direction}"}
end
The method works fine without the filter. Is something wrong with the filter method?! I've checked the tire doku....it should work.
Thanks! :)
Your issue is most probably being caused by using the default mappings for the status field, which would tokenize it -- downcase, split into words, etc.
Compare these two:
http://localhost:9200/myindex/_analyze?text=Text1&analyzer=standard
http://localhost:9200/myindex/_analyze?text=Text1&analyzer=keyword
The solution in your case is to use the keyword analyzer (or set the field to not_analyzed) in your mapping. When the field would not be an “enum” type of data, you could use the multi-field feature.
A working Ruby version would look like this:
require 'tire'
Tire.index('myindex') do
delete
create mappings: {
document: {
properties: {
status: { type: 'string', analyzer: 'keyword' }
}
}
}
store status: 'Test1'
store status: 'Test2'
refresh
end
search = Tire.search 'myindex' do
query do
filtered do
query { all }
filter :terms, status: ['Test1']
end
end
end
puts search.results.to_a.inspect
Note: It's rarely possible -- this case being an exception -- to offer reasonable advice when no index mappings, example data, etc. are provided.

Resources