Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Float with many digits automatically becomes BigDecimal when using Oj #67

Closed
kyoshidajp opened this issue Sep 18, 2023 · 0 comments · Fixed by #68
Closed

Float with many digits automatically becomes BigDecimal when using Oj #67

kyoshidajp opened this issue Sep 18, 2023 · 0 comments · Fixed by #68
Labels
bug Something isn't working

Comments

@kyoshidajp
Copy link
Contributor

Detail

If a document has coordinates field with [131.01468600332737, 43.0554632], then call Elastic::Transport::Client#perform_request like the following PoC.

# poc.rb

require 'elastic/transport'
require 'oj'

client = Elastic::Transport::Client.new(hosts: { host: "localhost", port: 9200})
body = {
  from: 0,
  size: 1,
  query: {
    match: {
      key: "5yc1x"
    }
  }
}

response = client.perform_request('GET', 'development/_search', {}, body)

coordinates = response.body['hits']['hits'][0]['_source']['coordinates']
p coordinates
p coordinates.map(&:class)
% bundle exec ruby poc.rb
[0.13101468600332737e3, 43.0554632]
[BigDecimal, Float]

But if remove require 'oj', then

% bundle exec ruby poc.rb
[131.01468600332737, 43.0554632]
[Float, Float]

This difference depends on the mode of oj used by MultiJson. MultiJson loads JSON with oj as strict mode by default.

> num_str = "1.11111111111111111"

> MultiJson.load(num_str).class
BigDecimal < Numeric

> Oj.load(num_str, {mode: :strict}).class
BigDecimal < Numeric

> Oj.load(num_str, {mode: :null}).class
BigDecimal < Numeric

> Oj.load(num_str, {mode: :compat}).class
Float < Numeric

> Oj.load(num_str, {mode: :rails}).class
BigDecimal < Numeric

> Oj.load(num_str, {mode: :object}).class
BigDecimal < Numeric

> Oj.load(num_str, {mode: :custom}).class
BigDecimal < Numeric

MultiJson allows other JSON engines to be selected, while all others remain Float.

What kind do we have trouble?

For example, when returning JSON value in an API endpoint, it is not possible to specify either a numeric or a string as the value type. Therefore, unintended type conversion is required only when using oj.

> Oj.load(num_str, {mode: :strict}).as_json
"1.11111111111111111"
> Oj.load(num_str, {mode: :strict}).as_json.class
String < Object

> Oj.load(num_str, {mode: :compat}).as_json
1.1111111111111112
> Oj.load(num_str, {mode: :compat}).as_json.class
Float < Numeric
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants