Applying more than one sort on a Tridion broker query - tridion

I have a broker query where I need to sort by 2 different fields (using JSP and 2011 SP1)
The API has the method "addSorting" which I am applying.
It appears, however, that the second addSorting call is overwriting the first addSorting call - rather than adding the second sort:
// Sort by Date
CustomMetaKeyColumn customMetaKeyColumnDate = new CustomMetaKeyColumn("date", MetadataType.DATE);
query.addSorting(new SortParameter(customMetaKeyColumnDate, SortParameter.DESCENDING));
// Sort by Owner
CustomMetaKeyColumn customMetaKeyColumnOwner = new CustomMetaKeyColumn("owner", MetadataType.STRING);
query.addSorting(new SortParameter(customMetaKeyColumnOwner, SortParameter.ASCENDING));
They sorts work fine individually.
Is this expected? Is addSorting really a setSorting - where only 1 sort can be specified or am I missing a way to combine 2 sorts?

The addSorting method works just fine. However, it simply does not work for CustomMeta columns!!! There is already a confirmed defect regarding this subject with the following summary: "SortParameter does not work with two metadata fields". This is still an open defect for 2011SP1 and is scheduled to be fixed only for the next release.
Cheers,
Daniel.

Related

Logic App using HTTP Action to access and GET Jira ticket

So I followed this answer and it works fine:
https://stackoverflow.com/a/74981947/20829088
Provided URL:
https://<YOUR_DOMAIN>.atlassian.net/rest/api/2/search?jql=project=<PROJECTID>&fields=issue,status,name&startAt=0&maxResults=8000
However, it take a lot of time. So, if I want the url to check for specific ticket depending on created time and type of ticket. For example
I want ticket that is created within 15 days and that are NOT a sub-task.
so I tried something like this.
.....&fields=issue,summary,issuetype&created>=-15d&hierarchylevel=0
I'm not sure of how it should be written I just tried this and it doesn't work.
Here is the request result in JSON:
It should be earthier [subtask=false] OR [hierarchylevel=0] OR [name=Task]
After reproducing from my end, I could able to achieve this using Condition connector of logic apps. I have initialized an array variable first and then tried to append each item that satisfies the condition. Below is the flow of my logic app.
and then I used Parse Json to retrieve the required values for condition comparision
You can use the below Code view to reproduce the same in your environment.
{"definition":{"$schema":"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#","actions":{"For_each":{"actions":{"Compose":{"inputs":"#items('For_each')?['fields']?['created']","runAfter":{},"type":"Compose"},"Condition":{"actions":{"Append_to_array_variable":{"inputs":{"name":"Array","value":"#items('For_each')"},"runAfter":{},"type":"AppendToArrayVariable"}},"expression":{"or":[{"greaterOrEquals":["#formatDateTime(outputs('Compose'),'yyyy-MM-dd')","#formatDateTime(addDays(utcNow(),-15),'yyyy-MM-dd')"]},{"equals":["#items('For_each')?['fields']?['issuetype']?['subtask']",false]},{"equals":["#items('For_each')?['fields']?['issuetype']?['hierarchyLevel']",0]},{"equals":["#items('For_each')?['fields']?['status']?['statusCategory']?['name']","Task"]}]},"runAfter":{"Compose":["Succeeded"]},"type":"If"}},"foreach":"#body('Parse_JSON')?['issues']","runAfter":{"Parse_JSON":["Succeeded"]},"type":"Foreach"},"HTTP":{"inputs":{"authentication":{"password":"<API_KEY>","type":"Basic","username":"<USERNAME>"},"method":"GET","uri":"https://jira#<ProjectName>.atlassian.net/rest/api/2/search?jql=project=<ProjectID>"},"runAfter":{},"type":"Http"},"Initialize_variable":{"inputs":{"variables":[{"name":"Array","type":"array"}]},"runAfter":{"HTTP":["Succeeded"]},"type":"InitializeVariable"},"Parse_JSON":{"inputs":{"content":"#body('HTTP')","schema":{"properties":{"expand":{"type":"string"},"issues":{"items":{"properties":{"expand":{"type":"string"},"fields":{"properties":{"aggregateprogress":{"properties":{"progress":{"type":"integer"},"total":{"type":"integer"}},"type":"object"},"aggregatetimeestimate":{},"aggregatetimeoriginalestimate":{},"aggregatetimespent":{},"assignee":{},"components":{"type":"array"},"created":{"type":"string"},"creator":{"properties":{"accountId":{"type":"string"},"accountType":{"type":"string"},"active":{"type":"boolean"},"avatarUrls":{"properties":{"16x16":{"type":"string"},"24x24":{"type":"string"},"32x32":{"type":"string"},"48x48":{"type":"string"}},"type":"object"},"displayName":{"type":"string"},"emailAddress":{"type":"string"},"self":{"type":"string"},"timeZone":{"type":"string"}},"type":"object"},"customfield_10001":{},"customfield_10002":{},"customfield_10003":{},"customfield_10004":{},"customfield_10005":{},"customfield_10006":{},"customfield_10007":{},"customfield_10008":{},"customfield_10009":{},"customfield_10010":{},"customfield_10014":{},"customfield_10015":{},"customfield_10016":{},"customfield_10017":{"type":"string"},"customfield_10018":{"properties":{"hasEpicLinkFieldDependency":{"type":"boolean"},"nonEditableReason":{"properties":{"message":{"type":"string"},"reason":{"type":"string"}},"type":"object"},"showField":{"type":"boolean"}},"type":"object"},"customfield_10019":{"type":"string"},"customfield_10020":{},"customfield_10021":{},"customfield_10022":{},"customfield_10023":{},"customfield_10024":{},"customfield_10025":{},"customfield_10026":{},"customfield_10027":{},"customfield_10028":{},"customfield_10029":{},"customfield_10030":{},"customfield_10033":{},"description":{},"duedate":{},"environment":{},"fixVersions":{"type":"array"},"issuelinks":{"type":"array"},"issuetype":{"properties":{"avatarId":{"type":"integer"},"description":{"type":"string"},"entityId":{"type":"string"},"hierarchyLevel":{"type":"integer"},"iconUrl":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"self":{"type":"string"},"subtask":{"type":"boolean"}},"type":"object"},"labels":{"type":"array"},"lastViewed":{},"priority":{"properties":{"iconUrl":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"self":{"type":"string"}},"type":"object"},"progress":{"properties":{"progress":{"type":"integer"},"total":{"type":"integer"}},"type":"object"},"project":{"properties":{"avatarUrls":{"properties":{"16x16":{"type":"string"},"24x24":{"type":"string"},"32x32":{"type":"string"},"48x48":{"type":"string"}},"type":"object"},"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"projectTypeKey":{"type":"string"},"self":{"type":"string"},"simplified":{"type":"boolean"}},"type":"object"},"reporter":{"properties":{"accountId":{"type":"string"},"accountType":{"type":"string"},"active":{"type":"boolean"},"avatarUrls":{"properties":{"16x16":{"type":"string"},"24x24":{"type":"string"},"32x32":{"type":"string"},"48x48":{"type":"string"}},"type":"object"},"displayName":{"type":"string"},"emailAddress":{"type":"string"},"self":{"type":"string"},"timeZone":{"type":"string"}},"type":"object"},"resolution":{},"resolutiondate":{},"security":{},"status":{"properties":{"description":{"type":"string"},"iconUrl":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"self":{"type":"string"},"statusCategory":{"properties":{"colorName":{"type":"string"},"id":{"type":"integer"},"key":{"type":"string"},"name":{"type":"string"},"self":{"type":"string"}},"type":"object"}},"type":"object"},"statuscategorychangedate":{"type":"string"},"subtasks":{"type":"array"},"summary":{"type":"string"},"timeestimate":{},"timeoriginalestimate":{},"timespent":{},"updated":{"type":"string"},"versions":{"type":"array"},"votes":{"properties":{"hasVoted":{"type":"boolean"},"self":{"type":"string"},"votes":{"type":"integer"}},"type":"object"},"watches":{"properties":{"isWatching":{"type":"boolean"},"self":{"type":"string"},"watchCount":{"type":"integer"}},"type":"object"},"workratio":{"type":"integer"}},"type":"object"},"id":{"type":"string"},"key":{"type":"string"},"self":{"type":"string"}},"required":["expand","id","self","key","fields"],"type":"object"},"type":"array"},"maxResults":{"type":"integer"},"startAt":{"type":"integer"},"total":{"type":"integer"}},"type":"object"}},"runAfter":{"Initialize_variable":["Succeeded"]},"type":"ParseJson"}},"contentVersion":"1.0.0.0","outputs":{},"parameters":{},"triggers":{"manual":{"inputs":{"schema":{}},"kind":"Http","type":"Request"}}},"parameters":{}}

How to read documents from Change Feed in Azure Cosmos DB since last checkpoint after restart?

I am using Change Feed processor library to read the Change Feed on a partitioned collection and below is the code for how I have configure it. I ma using most of the default options.
ChangeFeedProcessorOptions feedProcessorOptions = new
{
LeaseRenewInterval = TimeSpan.FromSeconds(15),
};
var docObserverFactory = DocumentFeedObserverFactory.Create(this.destinationCollectionInfo, this.dbRepository);
this.builder
.WithHostName(hostName)
.WithFeedCollection(this.monitoredCollectionInfo)
.WithLeaseCollection(this.leaseCollectionInfo)
.WithProcessorOptions(feedProcessorOptions)
.WithObserverFactory(docObserverFactory);
This runs fine as long as the Change Feed application is running and documents are being inserted/updated in the collection and the Change Feed app picks them up as expected.
The problem happens when I stop the Change Feed app for sometime and insert/update few documents in the Collection. Then when I start the Change Feed app, it doesn't pick changes from where it last left. Those changes that were inserted when the Change Feed app was stopped are lost. But when I set the flag StartFromBeginning to true, it picks everything from the start including changes that were inserted when the Change Feed app was stopped in between for sometime.
My understanding of read from current (StartFromBeginning to false) is that the Change Feed reads documents since it last left. But that doesn't seem to happen. Please help.
There are two ways to continue from exactly where you left it.
The first, and more accurate one, is to store the Continuation token of the last thing you read. That way you can specify it when you start again and it will win over both the StartTime and the StartFromBeginning flags.
The second one is to provide the StartTime property which will try and find the continuation token of a given time automatically. It has an approximate 5 second precision so there is a chance that you might miss some documents though.

Can't Edit/Update Certain Items In Database (Table)

I have database that I have multiple orders entered into. Everything seems to be working fine except for a few old entries which will not accept updates/changes to their Fields.
Note: The majority of the Fields are Strings with Possible Values entered via a DropDown Box.
So if I open Order A I can make adjustments just fine and those changes persist even after closing the page and coming back or refreshing.
But if I open Order B, I can make changes via the dropdowns and it looks like they have adjusted, however if I leave the page or refresh all the changes have reverted back.
One piece of info that may be helpful is that each of these orders has at least one Field that contains an entry that is no longer a Possible Value (the original entries were removed/changed per request of the client).
Maybe they are "locked" because of this? Is there a way to look at an error log for a Published app?
I can delete the "corrupt" entries and recreate them (since there are currently only a few), but I would prefer to find a better solution in case this happens again in the future.
Any help would be greatly appreciated.
It's a bug. Such field level value updates should get through.
As workaround you can update prohibited(not possible anymore) values with allowed ones in OnSave Model's Event like:
switch (record.Field) {
case "old_value_1":
record.Field = "new_value_1";
break;
case "old_value_2":
record.Field = "new_value_2";
break;
...
}
Sorry for the inconvenience.
Each deployment has its own log. Have you tried "App Settings > DEPLOYMENTS > (click on the desployment) > VIEW LOGS"?

Add custom text to AX 2012 drill-down links

I want to customize the standard drill-down functionality and add a text parameter to the drill-down URL. I will then parse and use the parameter in the SysStartUpCmdDrillDown or EventDrillDownPoller class like the solution provided by Jan B. Kjeldsen in this question.
The standard drill-down link is dynamics://Target/?DrillDown_RecID/ :
dynamics://0/?DrillDown_5637230378/
In previous versions of AX it was possible to modify the RecId to custom text and parse the text once the client is started:
dynamics://0/?DrillDown_0MenuItemName=PurchTable&FieldName=PurchId&FieldValue=P000044
Unfortunately, in AX 2012 the RecId is checked before the client is started and if it is not a valid int64, the drill-down event is not sent to the client. Since it is not possible to change the RecId to anything other than an integer, #Alex Kwitny suggested in the comments at that same question that you can add the custom text to the drill-down target like this:
dynamics://0MenuItemName=PurchTable/?DrillDown_5637230378/
The problem I experience with this is that the link now gets confused about which instance to start.
If the target is equal to the value in the System Admin -> system parameters -> Alerts ->Drill-down target, a client with the correct server instance is started. When I append the text with my custom text, it always starts the default instance(Which could be different from the instance I intended to start). While this is not ideal, I could work around this issue.
The bigger problem is that it now always starts a new session of the default instance, even if a client session is already started. As far as I can see I cannot write X++ code to solve this issue since the server instance is determined before any code in the client is executed.
My question is this - How can I add custom text to the drill-down link while preserving the way the client instance is started: If a client for the instance is already open, it should process the link in the open client, and not start up a new client of the default instance.
You should probably come up with another solution as mentioned in this post, but there could still be a way.
The URL has two objects that can be modified:
dynamics://[Drill-down target(str)]/?Drilldown_[Int64]
According to you, if you modify the [Drill-down target], then it launches AX using the default client config, and that is behavior that you don't want. If you have a matching [Drill-down target], it'll launch in the open client window, which is behavior I can't confirm, but I'll take it at face value and assume you're correct.
So that means the only thing you can modify in the URL is [int64]. This is actually a string that is converted to an int64 via str2int64(...), which in turn corresponds to a RecId. This is where it gets interesting.
This work all happens in \Classes\SysStartUpCmdDrillDown\infoRun.
Well, lucky for you the ranges for the objects are:
RecId - 0 to 9223372036854775807
Int64 - -9223372036854775808 to 9223372036854775807
You can call minRecId() and maxRecId() to confirm this.
So this means you have -9223372036854775808 to -1 numbers to work with by calling URLs in this range:
dynamics://0/?DrillDown_-1
to
dynamics://0/?DrillDown_-9223372036854775808
Then you would modify \Classes\SysStartUpCmdDrillDown\infoRun to look for negative numbers, and fork to your custom code.
HOW you decide to user these negative #'s is up to you. You can have the first n-digits be a table id or a look-up value for a custom table. You can't technically use a RecId as part of that negative number because in theory the RecId could get up that high (minus 1).

StructureGroup Details using the Content Delivery/Broker API

I am trying to get all the structure groups published in a given publication using the PublicationID. I am expecting to get the structure groups with StructureGroupCriteria by passing the Root Structure Group TCM ID but getting page ids (I am expecting SGs).
Now I am trying to loop through the list and get details of each structuregroup. I did not find any API (.net) to get these details and also the API is returning only Pages.
What I have done and working so far using StructureGroupCriteria, returns list of Page IDs instead of SG IDs
PublicationCriteria pubCriteria = new PublicationCriteria(pubID);
// Root StructureGroup TCM ID -- tcm:45-3-4
StructureGroupCriteria sgCriteria = new StructureGroupCriteria("tcm:45-3-4", true);
Criteria allSGsInPub = CriteriaFactory.And(pubCriteria, sgCriteria);
Query allSGs = new Query(allSGsInPub);
string[] sgInfo = allSGs.ExecuteQuery();
Response.Write("Total : " + sgInfo.Length);
foreach (string sgid in sgInfo ) {
// HOW DO I get the Structure Group Details here
//TCMURI sgURI = new TCMURI(sgid);
}
Q # 1 : How to get the all the structuregroups and individual structure group details? (May be something simple, I am not able to find right API).
Q # 2 : How can I get all the structuregroups using ItemTypeCriteria sgCriteria = new ItemTypeCriteria(4); // 4 is SG Item Type .
When I tried this option, the query worked successfully but no results returned. Is this the expected behavior and should we always use StructureGroupCriteria instead of ItemTypeCriteria?
The reason for this approach, I want to avoid using the Root StructureGroup ID which is required with the above code. But at the moment, none of the approaches returning StructureGroup information and I always get Page Information.
Tridion Version: 2011 SP1, .net API.
Note: When I publish I am checking the publish SG info checkbox and published successfully. On Broker DB side, I can see the information on the taxnonomy table as well.
I was playing with Odata service and accidentally I found that I can get all my structure group information from Odata web service.
/cd_webservice/odata.svc/StructureGroups?$filter=PublicationId%20eq%2045
Also, the results are returning child structure groups with a depth parameter.
Just to clarify , using Broker API it is not feasible to get the structure groups (my original question). However, the workaround solution is to use OData Service to get the Structure Groups.
I don't think you will get Structure Groups returned by the Query object.
According to the documentation, when you publish Structure Group information the Structure Group hierarchy is published to the Content Delivery side where it is stored as a taxonomy.
Have you tried using the Taxonomy APIs to get the information you need?

Resources