How to select for multiple conditions to return one object that matches those conditions - arrays

I am creating a test, and am trying to create a method that pulls a specific job posting ID when it matches the job posting title, the job type and the description, just in case that the case that there are more than one job posting with the same title.
I cannot get the select statement to pull the job posting ID out of the instance variable. Debugging shows that there is indeed the ID nested in the instance variable, but my conditions aren't being met because I am not doing it correctly.
#job_posting is the instance variable that contains the ID that I need, but I need my parameters in select to match so I can subsequently return the ID.
whenever I ONLY use posting title,such as:
target_postings = #job_postings.select{|posting|posting[:posting_title]}
it works and returns the ID I need, however I cannot do this:
def get_specific_posting_id_for_posting(posting_title, job_type, description)
expect(#job_postings.length > 0)
target_postings = #job_postings.select {|posting| posting[:posting_title] == posting_title; posting[:job_type] == job_type; posting[:description] == description}
expect(target_postings.length == 1)
target_posting = target_postings[0]
posting_id = target_posting[:posting_id]
posting_id
end

It looks like
target_postings = #job_postings.select {|posting| posting[:posting_title] == posting_title; posting[:job_type] == job_type; posting[:description] == description}
should probably be
target_postings = #job_postings.select do |posting|
posting[:posting_title] == posting_title
&& posting[:job_type] == job_type
&& posting[:description] == description
end
Your version has three separate checks, the first two of which do nothing, only the last statement in the block is actually being used to determine whether the item matches.
As an aside, since it looks like you only want the single first element that matches your conditions, you might want to consider using find instead of select. It works the same except it will stop iterating and return as soon as it finds the first matching item.

Related

Apex - Retrieving Records from a type of Map<SObject, List<SObject>>

I am using a lead map where the first id represents an Account ID and the List resembles a list of leads linked to that account such as: Map<id, List<Id> > leadMap = new Map< id, List<id> >();
My question stands as following: Knowing a Lead's Id how do I get the related Account's Id from the map. My code looks something like this, The problems is on the commented out line.
for (Lead l : leads){
Lead newLead = new Lead(id=l.id);
if (l.Company != null) {
// newLead.Account__c = leadMap.keySet().get(l.id);
leads_to_update.add(newLead);
}
}
You could put all lead id and mapping company id in the trigger then get the company id
Map<string,string> LeadAccountMapping = new Map<string,string>();//key is Lead id ,Company id
for(Lead l:trigger.new)
{
LeadAccountMapping.put(l.id,l.Company);
}
//put the code you want to get the company id
string companyid= LeadAccountMapping.get(l.id);
Let me make sure I understand your problem.
Currently you have a map that uses the Account ID as the key to a value of a List of Lead IDs - So the map is -> List. Correct?
Your goal is to go from Lead ID to the Account ID.
If this is correct, then you are in a bad way, because your current structure requires a very slow, iterative search. The correct code would look like this (replace your commented line with this code):
for( ID actID : leadMap.keySet() ) {
for( ID leadID : leadMap.get( actId ) ) {
if( newLead.id == leadID ) {
newLead.Account__c = actId;
leads_to_update.add(newLead);
break;
}
}
}
I don't like this solution because it requires iterating over a Map and then over each of the lists in each of the values. It is slow.
If this isn't bulkified code, you could do a Select Query and get the Account__c value from the existing Lead by doing:
newLead.Account__c = [ SELECT Account__c FROM Lead WHERE Id = :l.id LIMIT 1];
However, this relies on your code not looping over this line and hitting a governor limit.
Or you could re-write your code soe that your Map is actually:
Map<ID, List<Leads>> leadMap = Map<ID, List<Leads>>();
Then in your query where you build the map you ensure that your Lead also includes the Account__c field.
Any of these options should work, it all depends on how this code snippet in being executed and where.
Good luck!

get_by_id() not returning values

I am writing an application that shows the user a number of elements, where he has to select a few of them to process. When he does so, the application queries the DB for the rest of the data on these elements, and stacks them with their full data on the next page.
I made an HTML form loop with a checkbox next to each element, and then in Python I check for this checkbox's value to get the data.
Even when I'm just trying to query the data, ndb doesn't return anything.
pitemkeys are the ids for the elements to be queried. inpochecks is the checkbox variable.
preqitems is the dict to save the items after getting the data.
The next page queries nothing and is blank.
The comments are my original intended code, which produced lots of errors because of not querying anything.
request_code = self.request.get_all('rcode')
pitemkeys = self.request.get_all('pitemkey')
inpochecks = self.request.get_all('inpo')
preqitems = {}
#idx = 0
#for ix, pitemkey in enumerate(pitemkeys):
# if inpochecks[ix] == 'on':
# preqitems[idx] = Preqitems.get_by_id(pitemkey)
# preqitems[idx].rcode = request_code[ix]
# idx += 1
for ix, pitemkey in enumerate(pitemkeys):
preqitems[ix] = Preqitems.get_by_id(pitemkey)
#preqitems[ix].rcode = request_code[ix]
Update: When trying
preqitems = ndb.get_multi([ndb.Key(Preqitems, k) for k in pitemkeys])
preqitems returns a list full of None values, as if the db couldn't find data for these keys.. I checked the keys and for some reason they are in unicode format, could that be the reason? They look like so.
[u'T-SQ-00301-0002-0001', u'U-T-MT-00334-0007-0002', u'U-T-MT-00334-0008-0001']
Probably you need to do: int(pitemkey) or str(pitemkey), depending if you are using integer or string id

objectify filter empty values

How can I filter properly using Objectify 4 by several parameters, considering that some of those parameters can come empty, which would mean that I don't want to filter by those?
Example:
Please consider I want to filter something like this:
releases = ofy().load().type(Release.class)
.filter("user.name", searchCriteria.getName())
.filter("category", searchCriteria.getCategory())
.filter("city", searchCriteria.getCity()).list();
In order to match with what I said above, I have now the following code, checking every time which of my parameters come empty so I don't put them on the filter in that case:
if (!nameEmpty && !categoryEmpty && !cityEmpty) {
releases = ofy().load().type(Release.class)
.filter("user.name", searchCriteria.getName())
.filter("category", searchCriteria.getCategory())
.filter("city", searchCriteria.getCity()).list();
} else if (!nameEmpty && !categoryEmpty) {
releases = ofy().load().type(Release.class)
.filter("user.name", searchCriteria.getName())
.filter("category", searchCriteria.getCategory()).list();
} else if (!nameEmpty && !cityEmpty) {
releases = ofy().load().type(Release.class)
.filter("user.name", searchCriteria.getName())
.filter("city", searchCriteria.getCity()).list();
} else if ...
...
How can I avoid this crappy way of filtering and make it with just one line (or a few) using Objectify 4?
Query<Release> query = ofy().load().type(Release.class);
if (!nameEmpty)
query = query.filter("user.name", searchCriteria.getName());
if (!categoryEmpty)
query = query.filter("category", searchCriteria.getCategory())
if (!cityEmpty)
query = query.filter("city", searchCriteria.getCity());
releases = query.list();

Is there a way to link Save Results (for an insert DML operation) back to sObjects?

Background
I have a list of sObjects I need to insert, but I must first check if the insert will be successful. So, I'm setting a database save point before performing the insert and checking the save results (for the insert statement). Because, I don't want to process if any errors occurred, if there were any errors in the insert results, the database is rolled back to the save point.
Problem & Question
I need to collect the errors for each save (insert) result and associate each error to the specific sObject record that caused the error. According to the documentation Save results contain a list of errors, the Salesforce ID of the record inserted (if successful), and a success indicator (boolean).
How do I associate the Save Result to the original sObject record inserted?
Code/Example
Here's an example I put together that demonstrates the concept. The example is flawed, in that the InsertResults don't always match the sObjectsToInsert. It's not exactly the code I'm using in my custom class, but it uses the same logic.
Map<Id,sObject> sObjectsToInsert; // this variable is set previously in the code
List<Database.SaveResult> InsertResults;
Map<String,sObject> ErrorMessages = new Map<String,sObject>();
System.SavePoint sp = Database.setSavepoint();
// 2nd parameter must be false to get all errors, if there are errors
// (allow partial successes)
InsertResults = Database.insert(sObjectsToInsert.values(), false);
for(Integer i=0; i < InsertResults.size(); i++)
{
// This method does not guarantee the save result (ir) matches the sObject
// I need to make sure the insert result matches
Database.SaveResult ir = InsertResults[i];
sObject s = sObjectsToInsert.values()[i];
String em = null; // error message
Integer e = 0; // errors
if(!ir.isSuccess())
{
system.debug('Not Successful');
e++;
for(Database.Error dbe : ir.getErrors()) { em += dbe.getMessage()+' '; }
ErrorMessages.put(em, s);
}
}
if(e > 0)
{
database.rollback(sp);
// log all errors in the ErrorMessages Map
}
Your comment says the SaveResult list is not guaranteed to be in order, but I believe that it is. I've used this technique for years and have never had an issue.

Custom query with Castle ActiveRecord

I'm trying to figure out how to execute a custom query with Castle ActiveRecord.
I was able to run simple query that returns my entity, but what I really need is the query like that below (with custom field set):
select count(1) as cnt, data from workstationevent where serverdatetime >= :minDate and serverdatetime < :maxDate and userId = 1 group by data having count(1) > :threshold
Thanks!
In this case what you want is HqlBasedQuery. Your query will be a projection, so what you'll get back will be an ArrayList of tuples containing the results (the content of each element of the ArrayList will depend on the query, but for more than one value will be object[]).
HqlBasedQuery query = new HqlBasedQuery(typeof(WorkStationEvent),
"select count(1) as cnt, data from workstationevent where
serverdatetime >= :minDate and serverdatetime < :maxDate
and userId = 1 group by data having count(1) > :threshold");
var results =
(ArrayList)ActiveRecordMediator.ExecuteQuery(query);
foreach(object[] tuple in results)
{
int count = (int)tuple[0]; // = cnt
string data = (string)tuple[1]; // = data (assuming this is a string)
// do something here with these results
}
You can create an anonymous type to hold the results in a more meaningful fashion. For example:
var results = from summary in
(ArrayList)ActiveRecordMediator.ExecuteQuery(query)
select new {
Count = (int)summary[0], Data = (string)summary[1]
};
Now results will contain a collection of anonymous types with properties Count and Data. Or indeed you could create your own summary type and populate it out this way too.
ActiveRecord also has the ProjectionQuery which does much the same thing but can only return actual mapped properties rather than aggregates or functions as you can with HQL.
Be aware though, if you're using ActiveRecord 1.0.3 (RC3) as I was, this will result in a runtime InvalidCastException. ActiveRecordMediator.ExecuteQuery returns an ArrayList and not a generic ICollection. So in order to make it work, just change this line:
var results = (ICollection<object[]>) ActiveRecordMediator.ExecuteQuery(query);
to
var results = (ArrayList) ActiveRecordMediator.ExecuteQuery(query);
and it should work.
Also note that using count(1) in your hql statement will make the query return an ArrayList of String instead of an ArrayList of object[] (which is what you get when using count(*).)
Just thought I'd point this out for the sake of having it all documented in one place.

Resources