rails4, mongoid subtract two Criteria - ruby-on-rails

I have two Document, Picture, Seen_Picture
simply.
Class Picture
field :likes, type: Integer
field :is_new, type: Integer
end
and
Class SeenPicture
field :picture_id, type: String
field :is_new, type: Integer
field :user_id, type: String
end
I find Picture's is_new field is 1 and not SeenPicture
ex)
Picture(id, likes, is_new) :
[
[BSON::ObjectId('53f7fb5037646412e71b0000'), 2, 1],
[BSON::ObjectId('53f2aa8b6b6169e2eb010000'), 10, 1]
]
SeenPicture(id, picture_id, is_new, user_id) :
[
[BSON::ObjectId('53fbe7066b61694eb5000000'), '53f7fb5037646412e71b0000', 1, '53f2aa8b6b6169e2eb010000']
]
=> nonPicture is BSON::ObjectId('53f2aa8b6b6169e2eb010000') Picture's last document
when I use mysql
(Picture.all.pluck(:id) - SeenPicture.all.pluck(:id)).sample(1).first
In mongodb, how find nonSeen Picture Documents.

Related

Different requestBody Correct Method in Swagger OpenApi3

I have a form data like this:
{
"form_id": 55426,
"submission_id": 28,
"status": 1,
"user_id": "74285"
}
but sometimes status and user_id will not be passed and it will be like
and user and type_id will be there
{
"form_id": 55426,
"submission_id": 28",
"user": true,
"type_id" : 1
}
. So what is the correct method to define requestBody?
Is it correct to define like this,
requestBody:
description: Check integration status.
content:
application/json:
schema:
type: object
properties:
form_id:
type: integer
example: 236089
submission_id:
type: integer
example: 1
status:
type: integer
example: 236089
user_id:
type: integer
example: 1
user:
type: integer
example: 1
type_id
type: integer
example: 1
and in the tryout option, I should pass only relevant properties only? Or is there any option to describe differently multiple requestBody?

How to implement a method in ruby to load images from the backend app

I want to implement method in ruby to load images from the backend app but I don't know how. I have been trying with image_tag directly from a view to call the location /image/{imageId} or /image/{documentId} but no success obviously. This is what I get from the backend api:
[
{
"imageId": "1",
"srcDocumentId": 10000,
"scopes": null,
"teiId": "",
"name": "image",
"headline": "Fig. 1. ",
"description": "Fig. 1. GPA",
"inBody": true,
"image": "a long string",
"internalUrl": "image.png",
"source": "<figure xmlns=\"http://www.tei-c.org/ns/1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xml:id=\"fig_3\"><head>Fig. 1. </head><figDesc>Fig. 1. GPA</figDesc><graphic coords=\"4,130.95,64.62,360.00,502.42\" type=\"bitmap\" url=\"image.png\"/></figure>",
"ord": 0
}
]
Any help would be appreciated. Even if you tell me only the logic on how should I handle this in a model and then at the view.
Edit:
Let's say I want to show the headline and description of the image first. I have this in document_helper.rb :
def images_format(image)
m = []
m << [['Description:', image.description]] if image.description
m << [
['Headline', image.headline]
] if image.headline.any?
m
end
in document.rb I have this:
class Image
include Mongoid::Document
field :description, type: String
field :headline, type: String
field :image, type: String
field :imageId, type: String
field :image, type: String
field :srcDocumentId, type: Integer
field :internalUrl, type: String
field :name , type: String
field :internalUrl, type: String
field :source, type: String
end
and also this:
embeds_one :image, class_name: 'Document::Image'
embeds_one :image, class_name: 'Document::Image'
and in the view document_show.haml I put:
.document__body= images_format(#document.image)
I get this error: undefined method 'description' for nil:NilClass

Including nested association attributes in a count

I have classes that look like this:
class Orders < ActiveRecord::Base
has_many :items
has_many :types, through: :items
accepts_nested_attributes_for :items
end
class Item < ActiveRecord::Base
belongs_to :type
belongs_to :order
end
class Type < ActiveRecord::Base
has_many :items
end
An Order has several items on it, here's an overview and item and type:
<Item:0x00007fbcb185c170
id: 1,
finish: "Fir",
size: "38",
type_id: 8,
order_id: 1>
<Type:0x00007fbcace363e8
id: 8,
type: "Door",
name: "Jeldwen Premium Interior">
Items might have the same type but different finish and size attributes. I need to grab an order from the database and present them in a human readable format, something like this:
Order: {
Types:
{
Name: "Jeldwen Premium Interior",
Type: "Door",
Items:
{
finish: "fir",
size: "36",
quanity: "8" # sum of items in the database with same `finish` and `size`
},
{
finish: "fir",
size: "58",
quanity: "8" # sum of items in the database with same `finish` and `size`
}
}
I would like to be able to get all this information with one db call and I got part of the way there, I'm just missing type name-
`Order.where(id: 1).joins(:items).joins(:type).group("items.type_id", "items.size", "items.color").count`
Returns the type_id, size, finish, and quanity:
{[3, "36", "fir"]=>40,
[3, "48", "fir"]=>36,
[3, "36", "oak"]=>90,
[4, "48", "oak"]=>18}
I would like to return type.name and type.name with the count, is that possible? So a row would look something like:
["Jeldwen Premium Interior", "door", 3, "36", "fir"]=>40
I had this issue yesterday and I ended up using find_by_sql
you can test the sql in your sql console or at the following site
Your rails query
.joins(:items).joins(:type).group("items.type_id", "items.size", "items.color").count
can be done with sql
SELECT items.type_id, items.size, items.color, types.name, COUNT(types.id) AS NumberOfTypes, COUNT(types.name) AS NumberOfNames FROM items INNER JOIN types on items.id = types.item_id GROUP BY items.type_id, items.size, items.color;
in a scope
class Item
scope :items_count, -> { find_by_sql("SELECT items.type_id, items.size, items.color, types.name, COUNT(types.id) AS NumberOfTypes, COUNT(types.name) AS NumberOfNames FROM items INNER JOIN types on items.id = types.item_id GROUP BY items.type_id, items.size, items.color;") }
end
and you can call
items = Order.first.items_count
it will return an array of items, without count and without types. Something like:
=> [#<Item:0x00564d6bf08c28 id: nil, type: "type1test", size: 133, color: 'blue'>,
#<Item:0x00564d6bef7108 id: nil, type: "type1test", size: 136, color: 'blue'>,
#<Item:0x00564d6bef6e88 id: nil, type: "type1test", size: 137, color: 'blue'>,
#<Item:0x00564d6bef6cf8 id: nil, type: "type1test", size: 132, color: 'blue'>,
#<Item:0x00564d6bef6af0 id: nil, type: "type1test", size: 141, color: 'blue'>,
#<Item:0x00564d6bef68c0 id: nil, type: "type1test", size: 135, color: 'blue'>]
the items array will not have the types, but it will include a column numberofitems with the result of COUNT
items[0].numberoftypes
=> 6
items[0].numberofnames
=> 4
Anyway this will not work, because you can not GROUP BY different fields in different tables and have 2 COUNT at the same time.
You can try with sql to test it in this console and see that it is not possible.
It will not return the correct number of count for one of your columns, but this technique it is better then the one you are using right now, because you do not need to do 2 JOINS and it will return the objects.
SQL is very easy and you can refer to https://www.w3schools.com/sql/ to better understand any of the sql included in http://guides.rubyonrails.org/active_record_querying.html

Generate json with multiple records from DB (RoR)

I have the following code which is expected to return complex JSON containing data selected from DB by multiple parameters and includes data from other models:
def search
params[:beacon] = [{ 'id' => 1, 'prox_uuid' => 12345453453 }, { 'id' => 2, 'prox_uuid' => 5345634564536435 }]
beacons = Beacon.includes(:ads, :venue).where("id in (?) and proximity_uuid in (?)", params[:beacon][:ids], params[:beacon][:prox_uuids])
data = beacons.map { |beacon| {
id: beacon.id,
name: beacon.name,
:venue => {
id: beacon.venue.id,
name: beacon.venue.name,
logo: URI.join(request.base_url, beacon.venue.logo.url).to_s
},
ads: beacon.ads.inject([]) do |sum, add|
sum << {
id: add.id,
title: add.name,
cover: URI.join(request.base_url, add.file_url.url).to_s,
price: add.price,
description: add.description
}
end
}
}
render json: data.to_json
end
params[:beacon] = [{ 'id' => 1, 'prox_uuid' => 12345453453 }, { 'id' => 2, 'prox_uuid' => 5345634564536435 }] is a placeholder for array of parameters coming from POST request.
The problem is that I receive the following error at the query line:
no implicit conversion of Symbol into Integer
I also tried going through the array of parameters in the loop and querying each record however json generates only the last one.
You have params[:beacon][:ids] and params[:beacon][:prox_uuids] but params[:beacon] is an array, and so should be indexed by integer, eg. params[:beacon][0]. So the error is telling you that :ids (a Symbol) cannot be implicitly converted to an Integer in order to correctly reference into the params[:beacon] array.

MongoDB Mongoid delete value from array

I have mongodb document like this and want to remove one element form unpublished array
which is in resource_well
{
"_id": ObjectId("4fa77c808d0a6c287d00000a"),
"production_status": "Unscheduled",
"projected_air_date": null,
"published": false,
"resource_well": {
"published": [
],
"unpublished": {
"0": ObjectId("4fa795038d0a6c327e00000e"),
"1": ObjectId("4fa795318d0a6c327e00000f"),
"2": ObjectId("4fa795508d0a6c327e000011"),
"3": ObjectId("4fa796f48d0a6c327e000013")
}
},
"segment_status": "Draft",
}
Code in controller
segment = Segment.find(params[:segment_id])
# segment.resource_well[params['resource_well_type']].class => Array
# segment.resource_well[params['resource_well_type']].inspect => [BSON::ObjectId('4fa795038d0a6c327e00000e'), BSON::ObjectId('4fa795318d0a6c327e00000f'), BSON::ObjectId('4fa795508d0a6c327e000011'), BSON::ObjectId('4fa796f48d0a6c327e000013')]
segment.resource_well[params['resource_well_type']].delete(params[:asset_ids])
segment.save
Not able remove an element form array
Your ODM (or ORM) provides associations for you so that you can take advantage of having the ODM manage the links for you. So you should use the associations, otherwise you risk hanging yourself. Just make sure to specify the relationship correctly, and use the generated method named by the association and its methods, e.g. resource_well.unpublished <<, resource_well.unpublished.delete. The following models and tests work for me. The inconvenience is that the delete method on the association takes an object, e.g., other.delete(object) and not a string or conditions, so if you start with a string, you have to supply an object in order to delete it. Note that other.delete_all(conditions) or other.where(conditions).delete_all remove both actual documents as well as the association, which is not what you were looking for. Anyway, hope that this helps.
Models
class Segment
include Mongoid::Document
field :production_status, type: String
field :projected_air_date, type: Date
field :published, type: Boolean
field :segment_status, type: String
embeds_one :resource_well
end
class ResourceWell
include Mongoid::Document
embedded_in :segment
has_and_belongs_to_many :published, :class_name => 'Resource'
has_and_belongs_to_many :unpublished, :class_name => 'Resource'
end
class Resource
include Mongoid::Document
field :name, type: String
end
Test
require 'test_helper'
class Object
def to_pretty_json
JSON.pretty_generate(JSON.parse(self.to_json))
end
end
class SegmentTest < ActiveSupport::TestCase
def setup
Segment.delete_all
end
test 'resource_well unpublished delete' do
res = (0..3).collect{|i| Resource.create(name: "resource #{i}")}
seg = Segment.create(
production_status: 'Unscheduled',
projected_air_date: nil,
published: false,
resource_well: ResourceWell.new(unpublished: res[0..2]),
segment_status: 'Draft')
seg.resource_well.unpublished << res[3] #just an append example
puts seg.to_pretty_json
id = res[0]['_id'].to_s
puts "id: #{id}"
resource_obj = Resource.find(id)
puts "resource: #{resource_obj.inspect}"
Rails.logger.debug("delete: #{resource_obj.inspect}")
seg.resource_well.unpublished.delete(resource_obj)
puts Segment.find(:all).to_pretty_json
end
end
Result
# Running tests:
{
"_id": "4fa839197f11ba80a9000006",
"production_status": "Unscheduled",
"projected_air_date": null,
"published": false,
"resource_well": {
"_id": "4fa839197f11ba80a9000005",
"published_ids": [
],
"unpublished_ids": [
"4fa839197f11ba80a9000001",
"4fa839197f11ba80a9000002",
"4fa839197f11ba80a9000003",
"4fa839197f11ba80a9000004"
]
},
"segment_status": "Draft"
}
id: 4fa839197f11ba80a9000001
resource: #<Resource _id: 4fa839197f11ba80a9000001, _type: nil, name: "resource 0">
[
{
"_id": "4fa839197f11ba80a9000006",
"production_status": "Unscheduled",
"projected_air_date": null,
"published": false,
"resource_well": {
"_id": "4fa839197f11ba80a9000005",
"published_ids": [
],
"unpublished_ids": [
"4fa839197f11ba80a9000002",
"4fa839197f11ba80a9000003",
"4fa839197f11ba80a9000004"
]
},
"segment_status": "Draft"
}
]
.
Finished tests in 0.016026s, 62.3986 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 0 errors, 0 skips
db.collection.update(
{_id : ObjectId("4fa77c808d0a6c287d00000a")},
{ $unset : { "resource_well.unpublished.1" : 1 }}
);
This will remove element [1] of the array.
Also you can read how to implement it using mongoid: http://mongoid.org/docs/upgrading.html

Resources