Mongoid/mongodb indexing - mongodb

I am implementing a ruby on rails app with mongodb/mongoid and I am bit confused about the better indexing/searching structure.
I have a field staff in a model and a staff can be either of type - production, broker, office.
Each staff is a Person. Each type can have multiple staff.
So I have two approaches:
1). Make staff as an array and store it like
[{:key => 'broker', :name => "Broker Name", :person_id => "654978"},
{:key => 'office', :name => "Office Staff 1", :person_id => "564654"},
{:key => 'office', :name => 'another office', :person_id => '79878'}]
2). Make is a Hash and store is as
{:brokers => [{:person_id =>
2134, :name => 'Broker 1'}],
:office =>> [{:person_id =>
2131, :name => 'Office 1'}, {:person_id => 1231, :name => 'Office
2'}]}
I want to index these documents and should be able to search documents like, where office = '465456'.

If you store it as a hash you need several indexes. Since you then have to index the office name for each of the keys in the hash. If you store it as an array you only need 1 index.

It looks like you really want to store multiple indices; #bjartek is right, you'll want to store these as arrays:
class Office
include Mongoid::Document
embeds_many :people, as: :staff
# unsure for polymorphic embeds; perhaps this needs 'staff.name'
index "people.name"
index "people.person_id"
index "people.key"
end
http://mongoid.org/docs/indexing.html

Related

Drupal 8 - Entity Reference - Autocomplete - Add fields to search and result in autocomplete

I have an entity called "lawyers."
And another entity refers to lawyers.
The problem is that when searching the reference field with the autocompletion system many repeated names appear:
Pablo
Pablo
Pablo
Pablo
I need the reference field to be able to show the surnames of that person so that it turns out to be
Pablo Martínez
Paglo Gutirerrez
Pablo Iglesias
Pablo López
how can I do this?
You will have to create a Entity Reference View to use as handler for doing the autocomplete lookup. Then you can add additional fields (such as last name) to the autocomplete results. This article outlines that process well enough:
https://www.cmsminds.com/blog/entity-reference-entity-reference-view-in-drupal-8/
If the field is a base field and is not available on the Manage form Display page, you will have to modify the entity class Lawyer::baseFieldDefinitions function. Specifically, you need to change the handler and set the form display settings. In your BaseFieldDefinition::create call:
->setSetting('handler', 'default')
Needs to change to this:
->setSetting('handler', 'views')
->setSetting('handler_settings', [
'view' => [
'view_name' => 'name_of_entity_reference_view',
'display_name' => 'name_of_view_display',
],
])
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'weight' => 2,
'settings' => [
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
],
])
Alternatively, if you want to make base fields available in the UI, you can use this line to make the field available in the form display settings ui (and then export your form display settings as config:
->setDisplayConfigurable('form', TRUE);

How to do atomic operations like $push $pull $set etc. in Ecto MongoDB

I'm using mongodb_ecto and I want to know how can I do operations like $push or $pull on a deeply nested field? At the moment I write back the whole document which sometimes causes false data to be in the DB due to a race-condition.
Ok, I kind of figured it out. Do not use Ecto for this. In some cases you need the MongoDB positional operator and this can only be done directly via the Mongo-Adapter. Now for some usage examples:
I have a doucment with a list of options. Options have an ID, a label and list of userIDs who voted for this option.
BTW to generate an ObjectID (which is needed for talking directly to the MongoDB-Adapter) use this:
id = "584a5b9419d51d724d146e3f" # string form
value = (for <<hex::16 <- id>>, into: <<>>, do: <<String.to_integer(<<hex::16>>, 16)::8>>)
object_id = %BSON.ObjectId{value: value}
And now for some examples:
# update label of option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id}, # query
%{"$set" => %{"data.options.$.label" => new_label}} # update
)
# add new option to poll
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id},
%{"$addToSet" => %{"options" => %{label: label, id: random_new_id, votes: []}}}
)
# add user_id to option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id},
%{"$addToSet" => %{"options.$.votes" => user_id}}
)
# remove user_id form option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id},
%{"$pull" => %{"data.options.$.votes" => user_id}}
)

Zend Session webshop some items are just not stored

I have a weird problem where I want to store products from my shop in a session. This works well, except for some products. The shop is part of a cms where all products are rendered the same way. When someone adds a product to the shop this will be serialized and send with ajax to a script.
Almost all items are stored, but for some reason some items don't get stored. I can't find a connection or anything and I don't get any errors returned.
So this is the code that stores the product in a session:
$storeItemNumber = (string)$post['itemcode'];
$storeItem = array($storeItemNumber => array(
'title' => $post['title'],
'price' => $post['price'],
'quantity' => $post['quantity']
)
);
$shopSession->$storeItemNumber = $storeItem;
This is an example of a product that gets stored:
array('010101000' => array(
'title' => 'Product title - 15',
'price' => '28.95',
'quantity' => '1',
));
This is an example of a product that doesn't get stored:
array('400002001' => array(
'title' => 'Product title - Pink',
'price' => '5.50',
'quantity' => '1',
));
I already checked if the data gets through alright and it does right until the saving of it in a session.
What could possibly be a reason?
Had a look with a friend of mine and we both concluded it had something to do with the numbers. So I changed the function to the following and Now I'm able to add all the products without a problem.
I'll leave this question open for the time being, because I'm really curious why some numbers are stored and others not and what is a better/cleaner solution then mine.

Ruby on Rails Formtastic Multiple Options in Member_Label

I have a relational model where users have managers that are also users. The below code works great and does exactly what it's suppose to, but it's only displaying the first name of the manager. I'm trying to get this to show both the first name and the last name of the manager.
<%= sf.input :managers, :as => :check_boxes, :member_label => (:firstname) ,:input_html => { :size => 20, :multiple => true}%>
The other field i'm trying to add is the :lastname. I cannot figure out how to get :member_label to take both fields.
I figured it out. By using the Proc.new, I was able to add in both first name and last name.
<%= sf.input :managers, :as => :check_boxes, :member_label => Proc.new { |t| h(t.firstname + " " + t.lastname) } ,:input_html => { :size => 20, :multiple => true}%>

How do I make a DBIx::Class relationship with a fixed join condition?

We have a link table that can handle multiple types of object on one side, and I can't work out how to get from one of these objects to the link table using has_many.
Example: link table contains:
id link_id link_table resource_id
1 1 page 3
2 1 page 5
3 2 page 3
4 1 not_page 1
Building the relationship from the resource side is easy enough:
Resource->has_many(links => 'Link', 'resource_id');
but I haven't been able to get the corresponding relationship from the page side:
Page->has_many(links => 'Link', 'link_id');
would get the not_page link
Page->has_many(links => 'Link', {'foreign.link_id' => 'self.id', 'foreign.link_table' => 'page'});
gives an 'Invalid rel cond val page' error (which was not that surprising to me).
Page->has_many(links => 'Link', {'foreign.link_id' => 'self.id', 'foreign.link_table' => '"page"'});
gives an 'Invalid rel cond val "page"' error. Throwing backslashes in didn't help.
DBIx::Class::Relationship::Base says:
The condition needs to be an SQL::Abstract-style representation of the join between the tables
and I have tried various different options from there, such as:
Page->has_many(links => 'Link', {'foreign.link_id' => 'self.id', 'foreign.link_table' => {'=', 'page'}});
but without any success at all.
If I added another field to the page table which always contains the value 'page' I could do
Page->has_many(links => 'Link', {'foreign.link_id' => 'self.id', 'foreign.link_table' => 'self.what_table_am_i'});
but that's hardly an optimal solution.
Splitting the link table into a separate one for each type may be a possibility, but this is an existing project that is being considered for adaptation to DBIx::Class, and there may be other places where splitting a table into multiple other tables is more hassle than it's worth.
You should just make a wrapper method that calls the relationship with the required arguments:
Page->has_many(__all_links => 'Link', 'link_id');
sub links {
shift->__all_links({link_table => 'page'});
}
This would be pretty easy to turn into a DBIx::Class component if you have multiple tables that need to have this kind of join logic.
It can be specified in the has_many call like so:
Page->has_many(links => 'Link', 'link_id',
{ where => { link_table => 'page'} });
See: DBIx::Class Cookbook