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

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.

Related

Cannot create index on non-empty table

I'm currently using AWS Lambda (NodeJS) with AWS QLDB.
The scenario is like this.
I have the first table and its indexes when I deployed the service. So the table and indexes will be created. My problem is that, once I need to add new table and its indexes; it can't create the index because there's existing table.
My workaround to be able to create new table even if there's an existing table in my Ledger is that I'm querying the list of tables I have.
const getTables = async (transactionExecutor: TransactionExecutor) => {
const statement = `SELECT name FROM information_schema.user_tables`;
return await transactionExecutor.execute(statement);
};
Then I have this condition to check if the table is already existing
const tables = JSON.stringify(result.getResultList());
if (
!JSON.parse(tables).some((object): boolean => object.name === process.env.TABLE_NAME)
) {
console.log('TABLE A NOT EXISTING');
await createTable(transactionExecutor, process.env.TABLE_NAME);
}
if (
!JSON.parse(tables).some(
(object): boolean => object.name === process.env.TABLE_NAME_1,
)
) {
console.log('TABLE B NOT EXISTING');
await createTable(transactionExecutor, process.env.TABLE_NAME_1);
}
I don't know how to do it with indexes, I tried using SQL commands in QLDB but it's not working.
I hope you can help me.
Thank you
I'm not quite sure what your question is (the post title and body hint at different things), but I'm going to do my best to answer.
First, QLDB stores data in Ion, not JSON. So, please use the Ion APIs to parse data and not the JSON ones. The reason your code works at all is because Ion is a superset of JSON and the result set doesn't include types that are unknown to JSON. So, for example, if the result set was changed to include an Ion Timestamp, then your code would break.
Next, actually getting a list of tables has first class support in the driver. Simply use driver.getTableNames.
Third, I think you have a question "can I add an index to a non-empty table?". The answer is "no". This is planned functionality and I will update this answer when it is available. UPDATE: Now you can! https://aws.amazon.com/about-aws/whats-new/2020/09/amazon-qldb-launches-index-improvements/
Finally, I think you're also asking if there is a way to list indexes on a table in the same way as you can list tables in a ledger. The answer to that is 'yes'. The documents returned in information_schema.user_tables look like this:
{
tableId:"...",
name:"THE_TABLE_NAME",
indexes:[
{
expr:"[THE_FIELD_BEING_INDEXED]"
}
],
status:"ACTIVE"
}

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.

What is best method to get property for the content type with the closest match using client context (CSOM)?

I’m converting Event receiver codes into Remote event receiver using SharePoint 2013 Client context.
var documentList = clientContext.Web.GetList(Constants.DocumentsListUrl);
var classifiedContentTypeId = documentList.ContentTypes.BestMatch(new
SPContentTypeId("0x0120D52000155C54BB8DF04DE78D5F78461B236DEF"));
var classifiedContentType =
documentList.ContentTypes[classifiedContentTypeId];
Note that if the search finds two matches, the shorter ID is returned. For example, if 0x0101 is the argument, and the collection contains both 0x010109 and 0x01010901, the method returns 0x010109.
List.ContentTypes.BestMatch method is available to get closest match in SSOM. What is the right method in CSOM ?
Thanks in advance
One idea is to make use of the
ContentType.Id.IsChildOf()
method and then use string methods to choose the shortest Guid ?

Annotating a document with JAPE

I have been searching for a solution to this for weeks, I have some documents(about 95) that I am trying to classify using GATE. I have put them in one corpus I called training_corpus, however, after ANNIE has annotated the corpus, I have to go back into each file, select all token in the document, and create an annotation called Mention, with feature type and value the class for the document. for example:
type Start End id Features
Mention 0 70000 2588 {type=neg}
Is there anyway to automatically do this with JAPE? Basically, I want to select all tokens and create a new annotation with feature(type=class). Also, the class is appended to the document. Since there are many documents, can JAPE extract the class from the document name and set it to the value of Mentions feature. Example document name is neg_data1.txt, so the annotation will be Mention.type = neg?
Any help will be greatly appreciated. Thanks
I think you answered to your question by yourself.If the class assignment based on just a token present in text - why not simply process text outside of GATE?
For example to create an xml file like:
text and then use it in training process.
Also you can create a simple JAPE rule which will:
a) will take a text within document boundaries (see gate.Utils.length methods AFAIR)
b) based on presence of your token will create a new Annotation instance with features necessary.
an abstract example:
Phase: Instance
Input: Token
Options: control = once
Rule:Instance
(
{Token}
):instance
-->
{
AnnotationSet instances = outputAS.get("INSTANCE_ANNOTATION");
FeatureMap featureMap = Factory.newFeatureMap();
if (instances!=null&&!instances.isEmpty()){
featureMap.put("features when annotation presented in doc");
}else{
featureMap.put("features when annotation not in doc");
}
outputAS.add(new Long(0), new Long(documentLength), "Mention", featureMap);
}

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.