Activerecord: map one to one and retain duplicates - activerecord

I have an array with User IDs:
UserID = [
1
2
3
4
5
3
2
2
3]
I have a table that maps User ID to User Email. I'm trying to match IDs to Emails but retain duplicates so I end up with:
[
1#me.com
2#me.com
3#me.com
4#me.com
5#me.com
3#me.com
2#me.com
2#me.com
3#me.com]
When I try to pluck or map it like:
UserInfo.where(:id => UserID).pluck(:email)
I end up with:
[
1#me.com
2#me.com
3#me.com
4#me.com
5#me.com]
How can I get the table I'm looking for?

You will have to loop
ids.map{|id| UserInfo.find(id: id).email }
But of you have tons of ids you may want to optimize it by loading first just the records you need
email_hash = UserInfo.where(id: ids).inject({}) {|h, v| h[v.id] = v.email; h;}
result = ids.map{|id| email_hash[id]}

Related

How to query with contain array in Laravel?

Hi I have table that contain two foreign key as below.
symptom_diseases table
disease_id symptom_id
1 1
1 2
2 1
2 3
I would like to query with symptom_id array and return disease_id array. For example
symptom_id array = [1] then return disease_id [1,2]
symptom_id array = [1,2] then return disease_id [1]
symptom_id array = [1,3] then return disease_id [2]
symptom_id array = [2,3] then return null
I try to query using
whereIn
$diseaseArr = SymptomDisease::whereIn('symptom_id',$request->symptom)->pluck('disease_id')->toArray();
but I got wrong result. Any advice or guidance on this would be greatly appreciated, Thanks.
Firstly the whereIn query will get all models which match any of the entries in the array. You seem to want models which match all of them.
A naïve approach to do this would be something like:
$diseaseArr = SymptomDisease::whereIn('symptom_id',$request->symptom)
->select('disease_id')
->groupBy('disease_id')
->having(\DB::raw('COUNT(*)'),'=',count($request->symptom))
->pluck('disease_id')->toArray();
This will get all disease ids that occur the exact number of times as the number of symptoms you are looking for.
However you have made a pivot table into a model. That is usually a bad approach. I suggest you go about this via your Disease model (assuming one exists and has the relationships correctly set-up).
In which case you could do:
$disease = Disease::whereHas('symptoms',function ($query) use ($request) {
$query->whereIn('id', $request->symptom);
}, count($request->symptom))->get();
This should get all diseases which have all the symptoms specified in the $request->symptom array.

Unable to check if a list of int is completely contained in another int list

I have a list of int that represents service ids. and I want to make sure that all of those ids exist in the database.
In other words , I want to scan the list of ids and the table of services to make sure that all of these ids exist in the database.
I tried this :
List<int> ids;//[1,52]
var x = _context.Services.Any(s => ids.Contains(s.Id));//service ids = [1,2,3]
but it returned True , which is not the desired output.
I've also tried it this way :
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
and this way
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
with no luck as well. what is the right way to do it? I'm using EFCore 3.1.8
Normally you would use Queryable.Except for this.
If you have two sequence of items, and you do A except B, then if you have nothing left, then apparently every item from A is also an item in B.
IEnumerable<int> requiredIds = ...
IQueryable<int> serviceIds = dbContext.Services.Select(service => service.Id);
bool someRequiredIdsMissing = requiredIds.Except(serviceIds).Any();
Alas, your A is local and your B is in the database. So I guess this won't work.
What you can do, is to keep only Service Ids that are in the list of required Ids, and count them. If there are less, then apparently some requiredIds are not in serviceIds.
var requiredServiceIds = serviceIds.Where(serviceId => requiredIds.Contains(serviceId);
bool allRequiredAvailale = requiredServiceIds.Count() != requiredIds.Count();
Example:
IEnumerable<int> requiredIds = new [] {1, 2, 7, 20};
Total: 4 elements
Your service Ids are: 1 2 4 5 8 20 25
requiredServiceIds : 1 2 20: total 3 elements
So allRequiredAvailale is false;
Example 2:
Your service Ids are: 1 2 4 5 7 8 20 25
requiredServiceIds : 1 2 7 20: total 4 elements
So allRequiredAvailale is true;

Laravel - Eloquent group by

When I use group by, the results get grouped but not all of them are returned. Here I have six results but I only get five results. So basically room_id = 17 gets the entry 103 and entry 106 is not returned.
Here is what I am doing:
$prices = $hotel->prices()->groupBy('room_id')->get();
There is a way of grouping the like you desire. You can use groupBy() on the collection eloquent returns when it executes the query. The trick is to groupBy() after the database retrieving. Check this for more info.
An example would look like this:
$prices = $hotel->prices()->get(); // Returns a Collection of results
$prices = $prices->groupBy('room_id'); // Grouped by room_id
This will result in a collection that looks like:
[
'39' => [
// 1 row
],
'40' => [
// 1 row
],
'17' => [
// 2 rows
],
.....
]
The keys of this array will represent the room_id. On every key is this array will be another array containing the rows with the specified room_id.
Hope this helps :)

Ruby: Hash w/ Arrays, Returning Associated Key If Value Is In Array

New to Ruby and have run out of ideas. I have an array of books that I would like to 1) Shelve 2) Find which shelf it is on 3) Remove it from the associated shelf if found. For brevity I have an array of 6 books. Each shelf contains 5 books.
library_catalog = [ "Book1", "Book2", "Book3", "Book4", "Book5", "Book6" ]
shelves = Hash.new(0)
catalog_slice = library_catalog.each_slice(5).to_a
count = 1
catalog_slice.each do | x |
shelves.merge!(count=>x)
count+=1
end
From this I know have a Hash w/ arrays as such
{1=>["Book1", "Book2", "Book3", "Book4", "Book5"], 2=>["Book6"]}
This is where I'm having trouble traversing the hash to find a match inside the array and return the key(shelf). If I have title = "Book1" and I am trying to match and return 1, how would I go about this?
I think this should work.
shelves.select { |k,v| v.include?("Book1")}.keys.first
selected the hashes that have a value equal to the title you are looking for (in this case "Book1")
get the keys for these hashes as an array
get the first entry in the array.
to remove the Book from the shelf try this:
key = shelves.select { |k,v| v.include?("Book1")}.keys.first
shelves[key].reject! { |b| b == "Book1" }
get a reference to the array and then reject the entry you want to remove

Max sequence from a view containing multiple record using Linq lambda

I've been at this for a while. I have a data set that has a reoccurring key and a sequence similar to this:
id status sequence
1 open 1
1 processing 2
2 open 1
2 processing 2
2 closed 3
a new row is added for each 'action' that happens, so the various ids can have variable sequences. I need to get the Max sequence number for each id, but I still need to return the complete record.
I want to end up with sequence 2 for id 1, and sequence 3 for id 2.
I can't seem to get this to work without selecting the distinct ids, then looping through the results, ordering the values and then adding the first item to another list, but that's so slow.
var ids = this.ObjectContext.TNTP_FILE_MONITORING.Select(i => i.FILE_EVENT_ID).Distinct();
List<TNTP_FILE_MONITORING> vals = new List<TNTP_FILE_MONITORING>();
foreach (var item in items)
{
vals.Add(this.ObjectContext.TNTP_FILE_MONITORING.Where(mfe => ids.Contains(mfe.FILE_EVENT_ID)).OrderByDescending(mfe => mfe.FILE_EVENT_SEQ).First<TNTP_FILE_MONITORING>());
}
There must be a better way!
Here's what worked for me:
var ts = new[] { new T(1,1), new T(1,2), new T(2,1), new T(2,2), new T(2,3) };
var q =
from t in ts
group t by t.ID into g
let max = g.Max(x => x.Seq)
select g.FirstOrDefault(t1 => t1.Seq == max);
(Just need to apply that to your datatable, but the query stays about the same)
Note that with your current method, because you are iterating over all records, you also get all records from the datastore. By using a query like this, you allow for translation into a query against the datastore, which is not only faster, but also only returns only the results you need (assuming you are using Entity Framework or Linq2SQL).

Resources