I am trying to get a large list of workspace items and want to cut down my runtime. Currently my implementation creates a navigator on my project space, performs a GET request for a page of records, iterates through all the records on the page, and adds them to a ProjectList object one by one. This list is then displayed by a form. Ideally, I would like to be able to filter results before performing all the GET requests so I don't fetch records I don't need. Is there a quick way to filter out some records by their attributes before I GET them?
two APIs you can use, both can filter results.
/api/rest/v1/reports/{reportid} -- you need to define the report to fit your needs
/api/rest/v1/workspaces/{workspaceId}/views/{viewId} -- define the workspace view for the workspace
you may not call report object directly in script, but as reports are actually http calls, you may consider change the report call in your script and use it.
e.g. one of my report has URL
/reportRunAjaxRequestorAction.do?reportID=1709&workspaceID=21&reportTypeInRequest=reportTypeHtml&index(1__NEWROW)=&value(1__ALL_FILTER_FIELDS__NEWROW)=NAME_FILTER_META_DMS_TYPE_4&value(1__ALL_FILTER__NEWROW)=2&value(1__FILTER_VALUE__NEWROW)=mynewfiltervalue
I can change the filter value in the script to get a new report content.
You can also use the SEARCH endpoint:
POST api/rest/v1/workspaces/{id}/items/search
This returns a list of items in a workspace, pre-sorted and/or pre-filtered on as many fieldIds as you'd like to include.
It's a little tricky to use (read the documentation closely), but is much quicker than filtering the data after you've received it all in a GET request.
I have some examples in Python if you're interested.
I was looking through the documentation on the search and came across the part about the searchDefinition. I couldn't find an import for this, is this an object I should create or is there an import for it somewhere?
Once I have done the POST request how do I get the items that are left after the filtering?
Please ignore previous replies. I have figured out most everything, but I am having trouble making the objects for the search request. I have been using postman to debug my post requests and even when copying the example request exactly and changing values to match my schema, I'm still getting a 400:Bad Request response from the server. Just wanted to see if anyone had any feedback about what might be missing here?
{ "pageNo":1, "pageSize":10, "logicClause":"OR", "fields": [ { "fieldID":"NUMBER", "fieldTypeID":9 }, { "fieldID":"TEST", "fieldTypeID":4 }, { "fieldID":"TEST_NUMBER", "fieldTypeID" : 20 }, { "fieldID":"DATE", "fieldTypeID":3 } ], "sort" : [ { "fieldID":"TEST", "fieldTypeID":4 "sortDescending":false } ], "filter" : [ { "fieldID":"TEST", "fieldTypeID":4, "filterType" : { "filterID" : 4 }, "filterValue":"Please work" } ] }
Response is:
HTTP Status 400 - Bad Request
I have also tried removing the filter section and get the same response.
You really weren't kidding when you said read the doc carefully.
fieldTypeID refers to which tab you're looking for the field in. In our case, it was in item details (fieldTypeID = 0) Outlined here: http://help.autodesk.com/view/PLM/ENU/?guid=GUID-10176FF2-6DFB-4487-B98C-64637B607894
"filterType" : { "filterID" : 2 }, is referring to what type of search. 2 meaning "contains". Outlined here: http://help.autodesk.com/view/PLM/ENU/?guid=GUID-74B74433-47FC-4654-8569-607DBEEDD95E
Thanks everyone for the help. Give me 10 minutes and I'll run into another problem
Just so the next person doesn't have to decode the documentation, I'll share my C# class for searchDefinition as well as an example of its use.
Here's the class:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; //not really required, but useful namespace YOUR_NAMESPACE { public enum Operator { Contains = 2, StartsWith = 3, EndsWith = 4, DoesNotContain = 15, IsBlank = 20, NotBlank = 21, Is = 15 } public enum Tab { Undefined = -1, ItemDetails = 0, Workflow = 1, GridView = 2, LogInfo = 3, Attachment = 4, Linked = 5, BOM = 6, WhereUsed = 7, Relationship = 8, Sourcing = 9, Lifecycle = 10, WorkflowHistory = 11, Milestones = 12, BOM_Secure = 13, Associated_WF = 14, Descriptor = 15, AllFields = 99 } class searchDefinition { public int pageNo { get; set; } public int pageSize { get; set; } public String logicClause { get; set; } //Fields public List<fieldsItems> fields { get; set; } public class fieldsItems { public String fieldID { get; set; } public int fieldTypeID { get; set; } } //Sort public List<sortItems> sort { get; set; } public class sortItems { public String fieldID { get; set; } public int fieldTypeID { get; set; } public bool sortDescending { get; set; } } //Filter public List<filterItems> filter { get; set; } public class filterItems { public String fieldID { get; set; } public int fieldTypeID { get; set; } public filterTypeItems filterType { get; set; } public class filterTypeItems { public int filterID { get; set; } } public String filterValue { get; set; } } public String toJson() { return (JsonConvert.SerializeObject(this)); //again, not required, but useful } } }
Here's the implementation:
searchDefinition def = new searchDefinition { pageNo = 1, pageSize = 10, logicClause = "AND", fields = new List<searchDefinition.fieldsItems> { new searchDefinition.fieldsItems { fieldID = "NUMBER", fieldTypeID = (int)Tab.ItemDetails } }, sort = new List<searchDefinition.sortItems> { new searchDefinition.sortItems { fieldID = "NUMBER", fieldTypeID = (int)Tab.ItemDetails, sortDescending = false } }, filter = new List<searchDefinition.filterItems> { new searchDefinition.filterItems { fieldID = "TEST", fieldTypeID = (int)Tab.ItemDetails, filterType = new searchDefinition.filterItems.filterTypeItems { filterID = (int)Operator.Contains }, filterValue = "hello world" } } };
Pretty much just populate a searchDefinition object, serialize it, and stick it in the request body. Hopefully someone finds this useful. Cheers
Sorry for going completely dark there... sounds like you handled it!
As you clearly discovered, the kicker is just understanding WHERE in the documentation to find each of the required ID values. Both fieldTypeId and filterType are static (unless you modify them in your tenant, of course), so if your filter is going to be the same every time, you can hard code them into your request template.
Since you seemed to have nailed it, I'll just provide another JSON object example for fun.
This is used for searching a given part number, and returning any matching items with the fields Number, Description, Lifecycle Name, and Release Letter. Because the filter 'Latest Release' is set to 'Yes', this ought to only return a single value, assuming 'NUMBER' is an exact match.
search_term = "6-07454-01"
request_body = { "logicClause":"AND", "fields": [ { "fieldID":"NUMBER", "fieldTypeID":0 }, { "fieldID":"DESCRIPTION", "fieldTypeID":0 }, { "fieldID":"LIFECYCLE_NAME", "fieldTypeID":10 }, { "fieldID":"LC_RELEASE_LETTER", "fieldTypeID":10 }, ], "sort": [ { "fieldID":"NUMBER", "fieldTypeID":0, } ], "filter": [ { "fieldID":"NUMBER", "fieldTypeID":0, "filterType":{"filterID":15}, "filterValue":search_term #value to 'search' on }, { "fieldID":"LATEST_RELEASE", "fieldTypeID":10, "filterType":{"filterID":13}, "filterValue":"Yes" } ] }
#
Awesome. I'll probably end up creating some controller classes that will create the filtered request as well as deserialize the result. They'll have to be specific to the workspace, so I'll end up with a bunch of these controllers. I appreciate all of the help.