mongodb ruby delete_all nested document - ruby-on-rails

I'm trying to implement a delete_all within a nested document using MongoDB Ruby-Driver. It'll be incorporated within a bulk_write.
Model:
User
- Addresses # which is a nested model within User model
I can do this using Mongoid: user.addresses.delete_all
But I need to implement this using MongoDB Ruby Driver. I tried this but it's not working:
{
:update_one => {
:filter => { "_id" => customer.id },
:update => { "$unset" => { "addresses":{} } },
:upsert => false
}
}
I've also tried this and it doesn't work
{
:update_one => {
:filter => { "_id" => customer.id },
:update => { "$pullAll" => { :addresses => [{ :category => "default"}, { :category => "work"}] }},
:upsert => false
}
}
Any suggestions?

I figured it out, it should be:
{
:update_one => {
:filter => { "_id" => customer.id },
:update => { "$set" => { "addresses":[] } },
:upsert => false
}
}

Related

What is causing Aws::CloudFront::Errors::MalformedInput: Unexpected list element termination

I'm attempting to create a new AWS Cloudfront Distribution with v2 of the ruby AWS SDK and cannot figure out what is causing this error.
Aws::CloudFront::Errors::MalformedInput: Unexpected list element termination
client = Aws::CloudFront::Client.new
resp = client.create_distribution({
distribution_config: {
caller_reference: Time.now.to_i.to_s,
:aliases => {
:quantity => 1,
:items => [Name.generate_name]
},
:origins => {
:quantity => 1,
:items => [
{
:id => "#{self.id}-distribution",
:domain_name => "example-static.s3-website-us-east-1.amazonaws.com",
:origin_path => "/#{self.id}",
:custom_headers => {
:quantity => 0,
:items => []
},
:custom_origin_config => {
:http_port => 80,
:https_port => 443,
:origin_protocol_policy => "http-only",
:origin_ssl_protocols => {
:quantity => 3,
:items => ["TLSv1","TLSv1.1","TLSv1.2"]
}
}
}
]
},
:default_cache_behavior => {
:target_origin_id => "Custom-example-static.s3-website-us-east-1.amazonaws.com/#{self.id}",
:forwarded_values => {
:query_string => true,
:cookies => {
:forward => "none"
},
:headers => {
:quantity => 1,
:items => ["Origin"]
}
},
:trusted_signers => {
:enabled => false,
:quantity => 0
},
:viewer_protocol_policy => "allow-all",
:min_ttl => 0,
:allowed_methods => {
:quantity => 3,
:items => ["HEAD","GET","OPTIONS"],
:cached_methods => {
:quantity => 3,
:items => ["HEAD","GET","OPTIONS"]
}
},
:smooth_streaming => false,
:default_ttl => 86400,
:max_ttl => 31536000,
:compress => true
},
:cache_behaviors => {
:quantity => 0
},
:custom_error_responses => {
:quantity => 0
},
:comment => "",
logging: {
enabled: true, # required
include_cookies: false, # required
bucket: "example-logs", # required
prefix: "#{self.id}", # required
},
:price_class => "PriceClass_100",
:enabled => true,
:restrictions => {
:geo_restriction => {
:restriction_type => "none",
:quantity => 0
}
}
}
})
I compared the results I got back from an existing instance with
client = Aws::CloudFront::Client.new(:http_wire_trace => true)
resp = client.get_distribution_config({
:id => '<ID>'
})
Changing the payload from
:custom_headers => {
:quantity => 0,
:items => []
},
to
:custom_headers => {
:quantity => 0
},
seemed to fix the same error message for me.

rails - Elasticsearch completion suggester and search API

I'm using the search API, and now need to add the completion suggester, I'm using elasticsearch-rails gem.
When I search for an article, everything works
http://localhost:9200/articles/_search
"query": {
"multi_match": {
"query": "test",
"fields": [
"title", "tags", "content"
]
}
}
}
But since I've implemented the completion suggester I had to edit as_indexed_json to make it work, but now the search API doesn't work anymore, only the suggestions.
Here is my Article model:
def self.search(query)
__elasticsearch__.search(
{
query: {
multi_match: {
query: query,
fields: ['title', 'content', 'tags']
}
}
})
end
def self.suggest(query)
Article.__elasticsearch__.client.suggest(:index => Article.index_name, :body => {
:suggestions => {
:text => query,
:completion => {
:field => 'suggest'
}
}
})
end
def as_indexed_json(options={})
{
:name => self.title,
:suggest => {
:input => self.title,
:output => self.title,
:payload => {
:content => self.content,
:tags => self.tags,
:title => self.title
}
}
}.as_json
end
Is it possible to have _search and _suggest working together with the same model ?
I'm just digging into elasticsearch, but, as far as i understand, you can add what you had before modifying in the serializer function and recreate indices, they will live together well in the db. For example:
def as_indexed_json(options={})
{
:name => self.title,
:suggest => {
:input => self.title,
:output => self.title,
:payload => {
:content => self.content,
:tags => self.tags,
:title => self.title
}
}
}.as_json.merge(self.as_json) # or the customized hash you used
To avoid indices redundancy you can look at aliases and routing.

Add multiplie receivers to Paypal Mass Pay using Rails and 'paypal-sdk-merchant' gem

I'm creating an Rails application that must make use Paypal MassPayment API (adaptive payments is Not a option in our case).
I'm using the 'paypal-sdk-merchant' https://github.com/paypal/merchant-sdk-ruby
Following the sample suggested in
https://paypal-sdk-samples.herokuapp.com/merchant/mass_pay
I'm able to create a "mass payment" with ONE receiver:
#api = PayPal::SDK::Merchant::API.new
# Build request object
#mass_pay = #api.build_mass_pay({
:ReceiverType => "EmailAddress",
:MassPayItem => [{
:ReceiverEmail => "enduser_biz#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "3.00" } }] })
# Make API call & get response
#mass_pay_response = #api.mass_pay(#mass_pay)
# Access Response
if #mass_pay_response.success?
else
#mass_pay_response.Errors
end
The problem is: how can I build a mass pay object with multiple receiver?
Following the documentation, I tried the following code with a number of variations, but Paypal seems to considers only the last item:
#api = PayPal::SDK::Merchant::API.new
# Build request object
#mass_pay = #api.build_mass_pay({
:ReceiverType0 => "EmailAddress",
:MassPayItem0 => [{
:ReceiverEmail => "enduser_biz#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "3.00" } }],
:ReceiverType1 => "EmailAddress",
:MassPayItem1 => [{
:ReceiverEmail => "enduser_biz1#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "5.00" } }]
}
)
(...)
Also, I have an array of emails and values, so I need to all them in the mass pay, how can it be done?
Ideally, I would like something:
#mass_pay = build_mass_pay_with_array_of_email_and_values([ARRAY_OF_EMAILS_AND_VALUES_HERE])
The syntax is sort of like JSON would be. [] is an array, you would add more members to that MassPayItem array:
:MassPayItem => [{
:ReceiverEmail => "enduser_biz#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "3.00"
}
},
{
:ReceiverEmail => "enduser_biz2#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "1.00"
}
}]
ending up with:
require 'paypal-sdk-merchant'
#api = PayPal::SDK::Merchant::API.new
# Build request object
#mass_pay = #api.build_mass_pay({
:ReceiverType => "EmailAddress",
:MassPayItem => [{
:ReceiverEmail => "enduser_biz#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "3.00"
}
},
{
:ReceiverEmail => "enduser_biz2#gmail.com",
:Amount => {
:currencyID => "EUR",
:value => "1.00"
}
}]
})
# Make API call & get response
#mass_pay_response = #api.mass_pay(#mass_pay)
# Access Response
if #mass_pay_response.success?
else
#mass_pay_response.Errors
end
require 'paypal-sdk-merchant'
#api = PayPal::SDK::Merchant::API.new
#make an array of members
member_list = []
member_list << {
:ReceiverEmail => 'someone#example.com',
:Amount => {
:currencyID => "USD",
:value => 1.6
}
}
member_list << {
:ReceiverEmail => 'someone2#example.com',
:Amount => {
:currencyID => "USD",
:value => 1.6
}
}
# Build request object
#mass_pay = #api.build_mass_pay(member_list)
# Make API call & get response
#mass_pay_response = #api.mass_pay(#mass_pay)
# Access Response
if #mass_pay_response.success?
else
#mass_pay_response.Errors
end

Active resource param serialization issue

I'm trying to pass the following ruby hash into an active resource(3.0.9) find(:from) call.
my_hash = {
:p => {:s => 100, :e => 2},
:k => "blah",
:f => [
{
:fl => :bt,
:tp => :trm,
:vl => "A::B"
},
{
:fl => :jcni,
:tp => :trm,
:vl => [133, 134]
},
{
:mnfl => :bmns,
:mxfl => :bmxs,
:tp => :rfstv,
:vl => 1e5
},
{
:fl => :bpo,
:tp => :rftv,
:op => :eta,
:vl => 1.months.ago.strftime("%Y-%m-%d")
}
]
}
Resource.find_by_x_and_y(:all, :from => :blah, params: my_hash)
On the server side action, when I print the params hash, its all messed up. ( last 3 hashes in the array mapped to :f )
{
"f" => [
{
"fl" => "bt",
"tp" => "trm",
"vl" => "A::B"
},
{
"fl" => "jcni",
"tp" => "trm",
"vl" => [
"133",
"134"
],
"mnfl" => "bmns",
"mxfl" => "bmxs"
},
{
"tp" => "rfstv",
"vl" => "100000.0",
"fl" => "bpo",
"op" => "eta"
},
{
"tp" => "rftv",
"vl" => "2013-01-25"
}
],
"k" => "blah",
"p" => {
"e" => "2",
"s" => "100"
},
"action" => "blah",
"controller" => "x/Y",
"format" => "json"
}
my_hash.to_query gives me
f[][fl]=bt&f[][tp]=trm&f[][vl]=A%3A%3AB&f[][fl]=jcni&f[][tp]=trm&f[][vl][]=133&f[][vl][]=134&f[][mnfl]=bmns&f[][mxfl]=bmxs&f[][tp]=rfstv&f[][vl]=100000.0&f[][fl]=bpo&f[][op]=eta&f[][tp]=rftv&f[][vl]=2013-01-25&k=blah&p[e]=2&p[s]=100
which doesn't have indices, hence the mixup.
Is there a name for this type of serialization using "[]" ? Is this guaranteed to serialize/deserialize arbitrarily nested hashes/arrays/primitives faithfully ? How do I make active resource behave sanely ?

Advanced grouping in Ruby

I want to group events by their days.
Prefact:
Available days are 1,2,3,4,5,6,7
One event can not contain duplicates. e.g [1,1,2,3]
Setup is Ruby 1.9.2 with Rails 3.2
An event is containing like 8-10 more attributes(unnecessary to include in example, but should be considered, these attributes should still be there after grouping.) In other words the event objects should not be altered only grouped as is.
Consider an array with objects:
events = [
{
:name => "event1",
:days => [1,2,3,4,5]
},
{
:name => "event2",
:days => [1,4,5]
},
{
:name => "event3",
:days => [1]
},
{
:name => "event4",
:days => [2]
},
{
:name => "event5",
:days => [3]
},
{
:name => "event6",
:days => [4]
},
{
:name => "event7",
:days => [5]
},
{
:name => "event8",
:days => [1,2,3]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event11",
:days => [1,2,3,4,5]
}
]
To be grouped an event must have at least 3 days. And these days should be in numerically order.
Example(should be grouped): [1,2,3]
Example(should not be grouped): [1,4,5]
Events that's not suitable for grouping should be placed in each day they contain.
Example: [1,4,5] should be placed in 1,4 and 5.
The desired result of events array above:
[
{
:heading => "1",
:events => [
{
:name => "event3",
:days => [1]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "2",
:events => [
{
:name => "event4",
:days => [2]
},
{
:name => "event10",
:days => [1,2]
}
]
},
{
:heading => "3",
:events => [
{
:name => "event5",
:days => [3]
}
]
},
{
:heading => "4",
:events => [
{
:name => "event6",
:days => [4]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "5",
:events => [
{
:name => "event7",
:days => [5]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "1-3",
:events => [
{
:name => "event8"
}
]
},
{
:heading => "1.5",
:events => [
{
:name => "event1"
},
{
:name => "event11"
}
]
}
]
It is very advanced Ruby here. Maybe too advanced for me, everything I've tried ends up missing one part of the equation. But hey it's Ruby, it shouldn't be that hard?
EDIT: Updated example with clarification and corrected expected output
require 'pp'
pp(events.inject(Hash.new { |h, k| h[k] = [] }) do |m, e|
days = e[:days]
event = { :name => e[:name] }
if days.size >= 3 && days.last - days.first + 1 == days.size
m["%d-%d" % [days.first, days.last]] << event
else
days.each { |d| m[d.to_s] << event }
end
m
end)
I would modify DigitalRoss's answer slightly. I would change
if days.size >= 3 && days.last - days.first + 1 == days.size
to
if days.size >= 3 && (days.first..days.last).to_a == days
This will catch [1,1,3,4]...
It would also be wise to sort the days array before testing!

Resources