OR operator in Mongo 'update' $criteria - mongodb

I want to check for an existing record by matching either title or url fields. If either one matches, update that record. Otherwise, insert.
How do write the following properly (using Mongoid in Ruby):
articles.update(
{ **:title => story.title OR :url => story.url** },
{ :title => story.title, :url => story.url, :source => story.source, :last_updated => Time.now },
{ :upsert => true } )
Thanks!

You need do the request and update it like :
'''
articles.any_of({:title => xxx}, {:url => yyyy}).update( :foo => 'bar')
'''

Related

Elasticsearch searching with perl client

I'm attempting to do something that should be simple but I cannot get it to work. I've looked and search all over to find detailed doc for perl search::elsticsearch. I can only find CPAN doc and as far as search is concerned it is barely mentioned. I've search here and cannot find a duplicate question.
I have elasticsearch and filebeat. Filebeat is sending syslog to elasticsearch. I just want to search for messages with matching text and date range. I can find the messages but when I try to add date range the query fails. Here is the query from kibana dev tools.
GET _search
{
"query": {
"bool": {
"filter": [
{ "term": { "message": "metrics" }},
{ "range": { "timestamp": { "gte": "now-15m" }}}
]
}
}
}
I don't get exactly what I'm looking for but there isn't an error.
Here is my attempt with perl
my $results=$e->search(
body => {
query => {
bool => {
filter => {
term => { message => 'metrics' },
range => { timestamp => { 'gte' => 'now-15m' }}
}
}
}
}
);
This is the error.
[Request] ** [http://x.x.x.x:9200]-[400]
[parsing_exception]
[range] malformed query, expected [END_OBJECT] but found [FIELD_NAME],
with: {"col":69,"line":1}, called from sub Search::Elasticsearch::Role::Client::Direct::__ANON__
at ./elasticsearchTest.pl line 15.
With vars: {'body' => {'status' => 400,'error' => {
'root_cause' => [{'col' => 69,'reason' => '[range]
malformed query, expected [END_OBJECT] but found [FIELD_NAME]',
'type' => 'parsing_exception','line' => 1}],'col' => 69,
'reason' => '[range] malformed query, expected [END_OBJECT] but found [FIELD_NAME]',
'type' => 'parsing_exception','line' => 1}},'request' => {'serialize' => 'std',
'path' => '/_search','ignore' => [],'mime_type' => 'application/json',
'body' => {
'query' => {
'bool' =>
{'filter' => {'range' => {'timestamp' => {'gte' => 'now-15m'}},
'term' => {'message' => 'metrics'}}}}},
'qs' => {},'method' => 'GET'},'status_code' => 400}
Can someone help me figure out how to search with the search::elasticsearch perl module?
Multiple filter clauses must be passed as separate JSON objects within an array (like in your initial JSON query), not multiple filters in the same JSON object. This maps to how you must create the Perl data structure.
filter => [
{term => { message => 'metrics' }},
{range => { timestamp => { 'gte' => 'now-15m' }}}
]

Can't update description of listing with eBay API

I'm trying to write a Perl script that will update our eBay listings descriptions without having to keep logging in (running across multiple marketplaces if proving tricky to keep stock levels, descriptions etc updated). Here is what I have so far:
my $ebay = new Net::eBay( {
SiteLevel => 'prod',
DeveloperKey => 'x',
ApplicationKey => 'x',
CertificateKey => 'x',
Token => 'x',
} );
$ebay->setDefaults( { API => 2, compatibility => 900 } );
my $new_desc = q|<meta name="viewport" content="width=device-width, initial-scale=1.0">
<p>We are proud to announce our first ever badge! With an easy-to-iron
on backing, fitting couldn't be any easier! We have designed the path to
be a perfect addition to any piece of cosplay costume. Please do send
in the photos of it being used on your costumes, as we would love to
share.</p>
<p>The badge is 7 x 7 cm / 2 x 2 inches in size, and 2mm thi<br></p>|;
my $result = $ebay->submitRequest( "ReviseItem",
{
DetailLevel => "ReturnAll",
ErrorLevel => "1",
SiteId => "1",
Item => {
Description => \$new_desc,
ItemID => 253430606975
},
ItemID => 253430606975
}) || die;
print "Result: " . Dumper( $result ) . "\n";
I get an error when running it though:
'Errors' => [
{
'ShortMessage' => 'Return Policy Attribute Not Valid',
'ErrorClassification' => 'RequestError',
'ErrorCode' => '21920200',
'LongMessage' => 'Return Policy Attribute returnDescription Not Valid On This Site',
'SeverityCode' => 'Warning',
'ErrorParameters' => {
'Value' => 'returnDescription',
'ParamID' => '0'
}
},
{
'ShortMessage' => 'Description is missing.',
'ErrorClassification' => 'RequestError',
'ErrorCode' => '106',
'SeverityCode' => 'Error',
'LongMessage' => 'A description is required.'
}
],
Am I misunderstanding what gets passed in? from what I can understand, you just pass in the params you want to change?
UPDATE: As suggested by Dave, I'm giving Marketplace::Ebay a go. Just testing by trying to select one of my items:
my $ebay = Marketplace::Ebay->new(
production => 1,
site_id => 3,
developer_key => 'xx',
application_key => 'xx',
certificate_key => 'xxx',
token => 'xx',
xsd_file => 'ebaySvc.xsd',
);
my $res = $ebay->api_call('GetItem', { ItemID => 253430606975 });
print Dumper($res);
But I get some weird error:
error: element `{urn:ebay:apis:eBLBaseComponents}GiftIcon' not
processed for {urn:ebay:apis:eBLBaseComponents}GetItemResponse/Item at
//[5]/*[6] $VAR1 = undef;
Any ideas?
Ah ha - got it! The issue seemed to be around the way the HTML was being passed along. If I put it inside a CDATA tag, it works fine:
my $new_desc = q|<![CDATA[
some html etc here
]]>|;
my $result = $ebay->submitRequest( "ReviseItem",
{
DetailLevel => "ReturnAll",
ErrorLevel => "1",
SiteId => "1",
Item => {
Description => $new_desc,
ItemID => 253430606975
},
ItemID => 253430606975
}) || die;
...and updates perfectly

Handle Request: ChoicesType

So I have this ChoiceType Form that will sort the items:
$sort = $this->createForm(ChoiceType::class, NULL, array(
'choices' => array(
'...' => 'default',
'A-Z' => 'title_up',
'Z-A' => 'title_down',
'Price low to high' => 'price_up',
'Price high to low' => 'price_down',
),
));
I want to use the Choices so that when one of them is selected from the dropdown menu will do this: $products = "SELECT a FROM AppBundle:Product a ORDER BY a.title ASC".
I tried this:
$sort->handleRequest($request);
if($sort->isSubmitted() && $sort->isValid()) {
if (isset($default)) {
$products = "SELECT a FROM AppBundle:Product a ORDER BY a.title ASC";
return $this->render('AppBundle:main:index.html.twig', array('products' => $products, ));
}
}
But $default is not working, since is not defined. I dont know how to access the choices, so I can pass them to an if statement.
I think you need to write something like this:
$sort = $this->createFormBuilder()
->setAction($this->generateUrl('your_process_route_here'))
->setMethod('POST')
->add('select', ChoiceType::class, [
'placeholder' => 'Please select',
'choices' => [
'...' => 'default',
'A-Z' => 'title_up',
'Z-A' => 'title_down',
'Price low to high' => 'price_up',
'Price high to low' => 'price_down',
]
])
To get the value inside the <select> element:
$select = $request->request->get('select'); // this will contain whatever value you've selected from the dropdown
Check if the value is what you expect, and then create the query:
if ('default' == $select){ // or you can use a switch
// create a custom method inside your Repository class containing the SELECT, and call it here
}
That select from ->add('select', ...) will be the name attribute for your <select> html element.

pg_search_scope: chaining scopes seems impossible

I have a search form for searching "documents", that have a small dozen of search criterions, including "entire_text", "keywords" and "description".
I'm using pg_search_scope, but I have 2 different scopes.
This is in my document.rb:
pg_search_scope :search_entire_text,
:against => :entire_text,
:using => {
:tsearch => {
:prefix => true,
:dictionary => "french"
}
}
pg_search_scope :search_keywords,
:associated_against => {
:keywords => [:keyword]
},
:using => {
:tsearch => {
:any_word => true
}
}
Each separately works fine. But I can't do this:
#resultats = Document.search_keywords(params[:ch_document][:keywords]).search_entire_text(params[:ch_document][:entire_text])
Is there any way to work around this?
Thanks
I've never used pg_search_scope but it looks like you indeed can't combine two pg_search_scope's.
What you could do is use :search_entire_text with a pg_search_scope and use the resulting id's in a Document.where([1,2,3]) that way you can use standard rails scope's for the remaining keyword searches.
Example:
# If pluck doesn't work you can also use map(&:id)
txt_res_ids = Document.search_entire_text(params[:ch_document][:entire_text]).pluck(:id)
final_results = Document.where(id: txt_res_ids).some_keyword_scope.all
It works. Here's the entire code ... if ever this could help someone :
Acte.rb (I didn't translate to english, the explanations are commented to correspond to the question above)
pg_search_scope :cherche_texte_complet, #i.e. find entire text
:against => :texte_complet,
:using => {
:tsearch => {
:prefix => true,
:dictionary => "french"
}
}
pg_search_scope :cherche_mots_clefs, #find keywords
:associated_against => {
:motclefs => [:motcle]
},
:using => {
:tsearch => {
:any_word => true
}
}
def self.cherche_date(debut, fin) #find date between
where("acte_date BETWEEN :date_debut AND :date_fin", {date_debut: debut, date_fin: fin})
end
def self.cherche_mots(mots)
if mots.present? #the if ... else is necessary, see controller.rb
cherche_mots_clefs(mots)
else
order("id DESC")
end
end
def self.ids_texte_compl(ids)
if ids.any?
where("id = any (array #{ids})")
else
where("id IS NOT NULL")
end
end
and actes_controller.rb
ids = Acte.cherche_texte_complet(params[:ch_acte][:texte_complet]).pluck(:id)
#resultats = Acte.cherche_date(params[:ch_acte][:date_debut],params[:ch_acte][:date_fin])
.ids_texte_compl(ids)
.cherche_mots(params[:ch_acte][:mots])
Thanks !
chaining works in pg_search 2.3.2 at least
SomeModel.pg_search_based_scope("abc").pg_search_based_scope("xyz")

Mongoid strange query result

I'm using MongoDB through Mongoid with Rails 3 and observe this strange behavior when doing query in rails console:
> Table.where(:field => {"$exists" => true}).count
=> 3735
> Table.where(:field => {"$exists" => true}, :field => {"$ne" => ""}).count
=> 14878 # wtf???
> Table.where(:field => {"$exists" => true}, :field => "").count
=> 0 # at least it's not negative
> Table.where(:field => {"$exists" => false}).count
=> 11143
Since 11143 + 3735 = 14878, I assume that where(:field => {"$exists" => true}, :field => {"$ne" => ""}) also counts those records in which :field is not present (because nil != ""?). However, I believed conditions listed in #where would be joined with and, so it should match only those records where :field is not empty string AND is present.
You say "However, I believed conditions listed in #where would be joined with 'and'," but this is not correct. The conditions are a hash, and you have a collision on the key :field. Ruby silently uses the last value.
Please review the documentation for selection in Mongoid http://mongoid.org/en/origin/docs/selection.html, and use #and for a proper 'and' conjunction. Note that you can #inspect your query and examine the returned Criteria object. For example:
puts Table.where(:field => {"$exists" => true}, :field => {"$ne" => ""}).inspect
Hope that this helps.