Thinking Sphinx - How to give different weights to models when searching multiple models (global search) - thinking-sphinx

Let say I have two indexed models: User and Student.
I want to search on both models but give precedence to User. How can I do that?

Easy:
results = ThinkingSphinx.search(search_term,
:classes => [User, Student],
:index_weights => {'user_core' => 5},
)
student_core will implicitly have a weight of 1.

Related

How to create a relation for User, groups & groups metaData using TypeORM?

Creating the MySQL Table relationships, and confused to implement which Relationship should be implemented on User -> Groups -> GroupsMetaData.
User.id = OneToMany (Groups)
Groups = ManyToOne (Users)
Groups.id = ManyToMany (GroupsMetaData)
GroupsMetaData = ManyToOne(Groups)
Using TypeORM for implementing this approach.
Users.entity.ts
#OneToMany(type => Groups, groups => groups.uid)
groups:Groups[]
Groups.entity.ts
#ManyToOne(type => User, user => user.groups)
uid:User
Stucked to create the relations for Groups and GroupsMetaData.
Thanks
**It's not a professional way for an explanation, I tried for the best explanation
User entity
#OneToMany(type => Groups, groups => groups.uid)
groups:Groups[]
Group Entity
#ManyToOne(type => User, user => user.groups)
user: User
#ManyToOne(type => GroupMetadata, gmeta => gmeta.groups)
details: GroupMetadata
GroupMetadata Entity
#OneToMany(type => Groups, groups => groups.uid)
groups: Groups[]
With that config you'll have something like this:
A many to many relation between user and groupmetadata using group as junction table. I recommend you to change the name of some tables, group could be called "user_group" and group metadata can be renamed as group.
Let me know if this answers your question

How to use .findAll and find records from two different tables and a self reference?

I'm working with two tables in particular. Users and Friends. Users has a bunch of information that defines the User whereas Friends has two columns aside from id: user_id and friend_id where both of them are a reference to the User table.
I'm trying to find all of the users friends in as little calls to the db as possible and I currently have 2. One to retrieve the id of a user first from a request, then another to Friends where I compare the IDs from the first call and then a third call that passes the array of friends and find all of them in the Users table. This already feels like overkill and I think that with associations, there has to be a better way.
Modification of the tables unfortunately is not an option.
One thing that I saw from "http://docs.sequelizejs.com/manual/querying.html#relations---associations"
I tried but got an interesting error.. when trying to repurpose the code snippet in the link under Relations/Associations, I get "user is associated to friends multiple times. To identify the correct association, you must use the 'as' keyword to specify the alias of the association you want to include."
const userRecord = await User.findOne({
where: { id }
})
const friendsIDs = await Friends.findAll({
attributes: ["friend_id"],
where: {
user_id: userRecord.id
}
}).then(results => results.map(result => result.friend_id));
const Sequelize = require("sequelize");
const Op = Sequelize.Op;
return await User.findAll({
where: {
id: { [Op.in]: friendsIDs }
},
});
Above for my use case works. I'm just wondering if there are ways to cut down the number of calls to the db.
Turns out Sequelize handles this for you if you have the proper associations in place so yes, it was a one liner user.getFriends() for me.

Yii2: Hide search results based on permission

In my table I have:
PRODUCT
id_product
name
status
Where the status assumes the following values:
1 (Active)
2 (Inactive)
3 (Archived)
In the Product index view, I want the user to see certain statuses based on the permissions. Example:
Administrator sees records with statuses 1, 2, and 3.
Moderator views: 1 and 2
User views: 1
How can I do this? What alternatives do I have?
You could add conditions to your search model (I guess you have a ProductSearch.php file) so that results will be filtered based on user's role.
I've never used Yii's RBAC but I suppose you have a method to get user role, as described here: https://stackoverflow.com/a/25248246/4338862
So in your search model I would add, after grid filtering conditions, one or more conditions:
if($isUser) {
$query->andFilterWhere([
'status' => 1,
]);
}
elseif($isModerator) {
$query->andFilterWhere(['or',
['status' => 1],
['status' => 2]
]);
}
I can give you a more detailed answer if you need it.

Join DB tables with hasMany association - store in array

In a cakePHP application I am building, a profile can have multiple locations; the tables are called "profiles" and "locations" and in the model classes I have defined a HasMany relationship. Now I want the user to be able to search profiles based on their locations. After reading some questions here and the CakePHP Cookbook, I have decided I need to use SQL joins (in reality more tables are involved, and the result of a search should be based on conditions concerning different tables).
I have written the following function inside my Profile model:
public function findProfiles($long, $lat){
$options['joins'] = array(
array('table' => 'locations',
'alias' => 'Location',
'type' => 'Inner',
'conditions' => array('Location.profile_id = Profile.id'))
);
$options['order'] = array('Location.lng ASC'); //this is just as trial
return $this->find('all',$options);
}
The code works, but I get a copy of a profile for each location it possesses. That is, if a profile possesses 5 positions, I get five instances of that profile (each instance containing all five positions!)
How can I achieve this?
[edit]
eg. let's assume I only have one profile, with two positions. I get:
result[0][Profile]
[Position][0]
[1]
[1][Profile]
[Position][0]
[1]
Where the data in result[0] and result[1] is identical.
The problem happens because of the type of join used. With inner join you'll get this return with your query
profile_id location_id
---------------------------
1 2
1 3
And cake understands that as two records of Profile, so you get repeated Profiles with the same info.
If this were all the extent of your problem, I'd say "go with Containable behaviour and forget joins", but since you said there are more tables involved, maybe the type of join can't be changed. So to get the unique Profile without repetitions, you'll have to GROUP BY the query to get
profile_id location_id
---------------------------
1 2 & 3
with a code similar to this
$options['joins'] = array(
array('table' => 'locations',
'alias' => 'Location',
'type' => 'Inner',
'conditions' => array('Location.profile_id = Profile.id')),
'group' => 'Profile.id'
);
and you'll get rid of repetitions. For future problems like this, is best to first check the actual query that gets send to the DB, check yourself if the result that the DB gives you is what you want, and if not, see what you can do in cake to change it.

ActiveRecord select attributes without AR objects

I have a table with MANY rows, I need just the IDs of certain rows.
The slow way is to call
SomeARClass.find(:all, :conditions => {:foo => true}, :select => :id)
This returns AR Objects...
Is there a way to call a select on a class and have it return a plain old ruby data structure. Something like this:
SomeARClass.select(:id, :conditions => {:foo => true})
-> [1,2,3]
ActiveRecord::Base.connection.select_all(sql)
or
SomeARClass.connection.select_all(sql)
This is what you want to use. It returns an array of hashes. It should be used sparingly though. Hand coded sql is what ActiveRecord was built to replace. I only use in in really performance critical areas where constructing and returning AR objects is too slow.
The pluck method is exactly what you want, without compromising the SQL bad practice:
SomeARClass.where(:foo => true).pluck(:id)
I believe this should be the selected answer!
I don't think there is anything like SomeARClass.select(:id, :conditions => {:foo => true})
but you have two options
SomeARClass.find(:all, :conditions => {:foo => true}, :select => :id).map(&:id)
#=> [1,2,3,4]
id_hash = ActiveRecord::Base.connection.select_all('select id from tablename')
#=> [{"id"=>"1"}, {"id"=>"2"}, {"id"=>"3"}, {"id"=>"4"}]
id_hash.map(&:values).flatten
#=> ["1", "2", "3", "4"]
The second option returns only a hash and not Active record objects but it does looks a bit hackish.
Short answer:
Use .ids to fetch only ids
Use pluck to fetch ONLY some columns, but values will be PARSED by Active Record
Use ActiveRecord::Base.connection.select_all to fetch UNPARSED values.
Notes:
There is small difference between pluck and select_all:
If you pluck data - ActiveRecord map data to Ruby objects, like Dates, Enums,
Models, etc, and it could be different than you expect.
You can notice that the result below is a string:
2.5.1 :001 > ActiveRecord::Base.connection.select_all("select created_at from some_ar_class where id = 1 limit 1").rows.first
(0.6ms) select created_at from some_ar_classes where id = 1 limit 1
=> ["2018-10-01 01:12:31.758161"]
While pluck return Dates
2.5.1 :002 > SomeARClass.where(id: 1).pluck(:created_at).first.class
(0.4ms) SELECT "some_ar_classes"."created_at" FROM "some_ar_classes" WHERE "some_ar_classes"."id" = $1 [["id", 1]]
=> ActiveSupport::TimeWithZone
The same happens with Enums(int in database, but :symbols in Ruby)
And all this parsing/mapping operations also takes time. It's not a lot, but still. So if you asking for the most fast way to fetch data - its definitely raw sql query with connection.select_all, but there are very small situations when you can get some significant performance increase on that.
So my recommendation is using pluck.