Creating Groups out of two different lists - list

I guess this is an easy one but I have no clue how to do this.
I have two lists of Persons
List<Person> specificPersons
List<Person> allPersons
I would like to create groups out of the two complete lists like the following with linq.
IEnumerable<IGrouping<string, Person>> personsGroups
The string will be any custom string. I would use this to display both lists separated by a group header in a Windows 8.1 Metro Application ListView using a CollectionViewSource binding to the IEnumerable.

You can do something like this:
string headerSpecific = "Specific";
string headerAll = "All";
var query =
specificPersons.GroupBy(_ => headerSpecific )
.Union(
allPersons.GroupBy(_ => headerAll));
Note you have other ways to accomplish similar functionality (although not matching your question's requirements), for instance using anonymous types instead of groups:
var query =
specificPersons.Select(p => new { Header = headerSpecific, p})
.Union(
allPersons.Select(p => new { Header = headerAll, p}));

I would suggest adding a Group property to Person, which you can set via a simple loop on each of your lists. Then you can do this:
IEnumerable<IGrouping<string, Person>> personsGroups = specificPersons.Concat(allPersons).GroupBy(p => p.Group);
Note that this would not make sense if Person is a domain entity and/or exists in your database. Since these groups are for display purposes, use a view model (e.g. PersonViewModel) and add the Group property to that model to avoid changing your domain model.

Related

Google Healthcare API Nodejs - Filter Appointment using start and end date

I cannot filter an Appointment from start and end date using the google healthcare API.
I am trying to recreate the query below:
Appointment?date=ge2023-02-03T04:00:00.000Z&date=le2023-02-05T04:00:00.000Z
This is my javascript code using the library:
const parent = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;
const params = {
parent,
resourceType,
date: `le${end}`,
date: `ge${start}`,
};
const resource = await healthcare.projects.locations.datasets.fhirStores.fhir.search(params);
date: `ge${start}` is ignored because you cannot duplicate the same key.
Is there any other way I can achieve this.
Thanks!
I was able to make it work.
const params = {
parent,
resourceType,
"date:end": `le${end}`,
"date:start": `ge${start}`,
};
Just change "date" to "date:start" and "date:end"
I see that you were able to make this work, but there's a better way. What you essentially want to do here is specify multiple date parameters. The solution that you've come up with does this, but by using non-existent modifiers, :start and :end. By default the FHIR store drop modifiers it does not recognize, so your query as the same as date=le...&date=ge..., which is the end result you want. But if you were using the header Prefer: handling=strict, or set defaultSearchHandlingStrict in your FHIR store config, you'll get an error back from this search.
So what's the correct thing to do? If you want to specify multiple query parameters to be ANDed together (with the Node API), all you need to do is specify an array. In the future, if you wanted to OR them together you would use a single parameter with a comma separated list. So your code becomes
const params = {
parent,
resourceType,
date: [`le${end}`, `ge${start}`],
};
As a side note, the behaviour of search with the resourceType parameter is undefined, the method you want is searchType. These look the same due to the way the code is generated, but they function slightly differently.

Search custom property in SharePoint User Profile

I created a custom property in the user profile.
I want to search through all the user profiles and output those profiles in which the custom property contains a certain string
For example:
User1- Custom Property value is 1,2,3
User2- Custom Property value in 2,4,5
User3- Custom Property value is 4,6,8
I want to output all the profiles in which Custom Property contains 2
(using c# code)
So the output should have User1 and User2
Can someone suggest the best way to implement this?
I did find some links in the internet for searching user profiles use KeyWord search but and not sure if those methods could be used to search through Custom Properties.
Example: https://www.collaboris.com/how-to-use-search-keywordquery-to-query-user-profiles-in-sharepoint/
I am using SharePoint 2013
We ended up promoting the Custom Property that we added to the User profile to a Managed property.
Also it seems like we can do wildcard searches on managed properties so we do People searches like "CustomProperty:*,2,*" so that it would return all the user profiles which have the number 2 in the custom property of their user profile
Interestingly the wildcard works only on the end for OOTB properties like FirstName so we cant do things like FirstName:oh and expect it would return John Doe's profile
But we can certainly do this - FirstName:joh* and that would return all the people whose first name starts with Joh (which would include John Doe)
But it seems like the wildcard works both at the beginning and the end for the custom managed properties (which helped a great deal for us)
On how to return the results of the search using c# we used this-
private DataTable GetPeople(SPSite spSite, string queryText)
{
var keywordQuery = new KeywordQuery(spSite)
{
QueryText = queryText,
KeywordInclusion = KeywordInclusion.AllKeywords,
SourceId = System.Guid.Parse("b09a7990-05ea-4af9-81ef-edfab16c4e31")
};
keywordQuery.RowLimit = this.MaxProfilesToDisplay;
keywordQuery.SelectProperties.Add("AccountName");
keywordQuery.SelectProperties.Add("PictureURL");
SearchExecutor e = new SearchExecutor();
ResultTableCollection rt = e.ExecuteQuery(keywordQuery);
var tab = rt.Filter("TableType", KnownTableTypes.RelevantResults);
var result = tab.FirstOrDefault();
DataTable DT = result.Table;
return DT;
}
and we would invoke this like
DataTable dt = GetPeople(SPContext.Current.Site, "CustomProperty:*,2,*" );

spring data neo4j (SDN4) - find by relationship

I'm studying spring data for Neo4J and I've seen some examples where you just define a method in the repository interface following some standards (to find by a specific attribute) and it's automatically handled by spring. Ex: findByName.
It works quite straightforward with basic attributes but it doesn't seems to work when the attribute is actually a relationship.
See this example:
public class AcceptOrganizationTask extends AbstractTask {
#Relationship(type="RELATES_TO", direction = "OUTGOING")
private OrganizationInvite invitation;
...
}
In the repository interface I've defined 3 methods (All with the same goal):
List<AcceptOrganizationTask> findAllByInvitation(OrganizationInvite invite);
#Query("MATCH (i:OrganizationInvite)<-[RELATES_TO]-(t:AcceptOrganizationTask) WHERE i={invite} RETURN t")
List<AcceptOrganizationTask> getTaskByInvitation(#Param("invite") OrganizationInvite invite);
AcceptOrganizationTask findByInvitation_Id(Long invitationId);
None of them are able to retrieve the task by its invite property. But if I use use findAll() I can get the object with the property associated to the correct invitation.
Am I missing something ?
Bellow I have the Cypher code generated for this three methods:
findAllByInvitation
MATCH (n:`AcceptOrganizationTask`)
WHERE n.`invitation` = { `invitation_0` }
WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)
with params {invitation_0={entityId=15, version=0, createdOn=1484758262374, lastChanged=1484758262374, createUser=null, lastUpdatedBy=null, email=user2#acme.com, randomKey=fc940b14-12c3-4894-b2b4-728e3a6b8036, invitedUser={entityId=11, version=0, createdOn=1484758261450, lastChanged=1484758261450, createUser=null, lastUpdatedBy=null, name=User user2#acme.com, email=user2#acme.com, credentialsNonExpired=true, lastPasswordResetDate=null, authorities=null, authoritiesInDB=[], accountNonExpired=true, accountNonLocked=true, enabled=true, id=11}, id=15}}
getTasksByInvitation
MATCH (i:OrganizationInvite)<-[RELATES_TO]-(t:AcceptOrganizationTask)
WHERE i={invite} RETURN t with params {invite=15}
findByInvitation_Id
MATCH (n:`AcceptOrganizationTask`)
MATCH (m0:`OrganizationInvite`)
WHERE m0.`id` = { `invitation_id_0` }
MATCH (n)-[:`RELATES_TO`]->(m0)
WITH n
MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)
with params {invitation_id_0=15}
All entities inherit from a common AbstractEntity with and Long id field, annotated with #GraphId.
Am I missing something ?
At the moment derived finder queries support only works to one level of nesting.
We are hoping to add this feature soon in the coming weeks though.
For now you can write a custom #Query to get around this.

How to query based on one-to-many relationships in Spring Data Neo4j

I have defined simple one-to-many relationship as:
#Relationship(type = "BELONG")
private Set<Category> categories;
I want to query all the objects based on the exact set of Category. i.e. implement something like:
Page<SomeObject> findAllByCategories(Set<Category> categories, PageRequest page);
What is the best way to do it in Spring Data Neo4j?
You have a couple of options on how you can do this.
Your calling code can simply call the following on your SomeObjectRepository:
Iterable<Long> ids = categories.stream().map(SomeObject::getId).collect(Collectors.toSet());
Iterable<SomeObject> someObjects = someObjectRepository.findAll(ids, 1);
Note this method does not support paging though.
Another way is to inject a Session into your calling code and either write a custom Cypher query to retrieve the objects you want or use the load all by instance method:
#Autowired
private Session session;
...
// Option 1: write some cypher
Map<String, Object> params = new HashMap<>():
params.put("ids", ids) // use a stream like above to collect the ids.
Iterable<SomeObject> someObjects = session.query(SomeObject.class, "MATCH (n:SomeObject) ...", params);
//Option 2: use the load by instances method which also allows pagination:
Collection<SomeObject> someObjects = session.loadAll(categories, new Pagination(0, 25));
My recommendation would be option 2 as it pretty much does exactly what you want.

Sitecore Multisite Manager and 'source' field in template builder

Is there any way to parametise the Datasource for the 'source' field in the Template Builder?
We have a multisite setup. As part of this it would save a lot of time and irritation if we could point our Droptrees and Treelists point at the appropriate locations rather than common parents.
For instance:
Content
--Site1
--Data
--Site2
--Data
Instead of having to point our site at the root Content folder I want to point it at the individual data folders, so I want to do something like:
DataSource=/sitecore/content/$sitename/Data
I can't find any articles on this. Is it something that's possible?
Not by default, but you can use this technique to code your datasources:
http://newguid.net/sitecore/2013/coded-field-datasources-in-sitecore/
You could possibly use relative paths if it fits with the rest of your site structure. It could be as simple as:
./Data
But if the fields are on random items all over the tree, that might not be helpul.
Otherwise try looking at:
How to use sitecore query in datasource location? (dynamic datasouce)
You might want to look at using a Querable Datasource Location and plugging into the getRenderingDatasource pipeline.
It's really going to depend on your use cases. The thing I like about this solution is there is no need to create a whole bunch of controls which effectively do he same thing as the default Sitecore ones, and you don't have to individually code up each datasource you require - just set the query you need to get the data. You can also just set the datasource query in the __standard values for the templates.
This is very similar to Holger's suggestion, I just think this code is neater :)
Since Sitecore 7 requires VS 2012 and our company isn't going to upgrade any time soon I was forced to find a Sitecore 6 solution to this.
Drawing on this article and this one I came up with this solution.
public class SCWTreeList : TreeList
{
protected override void OnLoad(EventArgs e)
{
if (!String.IsNullOrEmpty(Source))
this.Source = SourceQuery.Resolve(SContext.ContentDatabase.Items[ItemID], Source);
base.OnLoad(e);
}
}
This creates a custom TreeList control and passes it's Source field through to a class to handle it. All that class needs to do is resolve anything you have in the Source field into a sitecore query path which can then be reassigned to the source field. This will then go on to be handled by Sitecore's own query engine.
So for our multi-site solution it enabled paths such as this:
{A588F1CE-3BB7-46FA-AFF1-3918E8925E09}/$sitename
To resolve to paths such as this:
/sitecore/medialibrary/Product Images/Site2
Our controls will then only show items for the correct site.
This is the method that handles resolving the GUIDs and tokens:
public static string Resolve(Item item, string query)
{
// Resolve tokens
if (query.Contains("$"))
{
MatchCollection matches = Regex.Matches(query, "\\$[a-z]+");
foreach (Match match in matches)
query = query.Replace(match.Value, ResolveToken(item, match.Value));
}
// Resolve GUIDs.
MatchCollection guidMatches = Regex.Matches(query, "^{[a-zA-Z0-9-]+}");
foreach (Match match in guidMatches)
{
Guid guid = Guid.Parse(match.Value);
Item queryItem = SContext.ContentDatabase.GetItem(new ID(guid));
if (item != null)
query = query.Replace(match.Value, queryItem.Paths.FullPath);
}
return query;
}
Token handling below, as you can see it requires that any item using the $siteref token is inside an Site Folder item that we created. That allows us to use a field which contains the name that all of our multi-site content folders must follow - Site Reference. As long at that naming convention is obeyed it allows us to reference folders within the media library or any other shared content within Sitecore.
static string ResolveToken(Item root, string token)
{
switch (token)
{
case "$siteref":
string sRef = string.Empty;
Item siteFolder = root.Axes.GetAncestors().First(x => x.TemplateID.Guid == TemplateKeys.CMS.SiteFolder);
if (siteFolder != null)
sRef = siteFolder.Fields["Site Reference"].Value;
return sRef;
}
throw new Exception("Token '" + token + "' is not recognised. Please disable wishful thinking and try again.");
}
So far this works for TreeLists, DropTrees and DropLists. It would be nice to get it working with DropLinks but this method does not seem to work.
This feels like scratching the surface, I'm sure there's a lot more you could do with this approach.