SharePoint CAML View Elements index - sharepoint

I find it hard to find available elements I can use when creating Views. Also on MSDN they are paginated over 3 pages.
Would be nice if this could be improved with examples like what can we do with these properties, because MS documentation does not provide that.
So here they are:
Aggregations
Batch
Case
Column
Column2
ContentTypes
Counter
CurrentRights
Default
Else
Expr
Expr1
Expr2
Field
FieldPrefix
FieldProperty
FieldRef
Fields
FieldSortParams
FieldSwitch
FilterLink
ForEach
GetFileExtension
GetVar
GroupByFooter
GroupByHeader
HTML
HttpHost
HttpPath
HttpVDir
ID
Identity
IfEqual
IfHasRights
IfNeg
IfNew
IfSubString
Join
Joins
Length
Limit
List
ListProperty
ListUrl
ListUrlDir
LookupColumn
MapToAll
MapToControl
MapToIcon
MeetingProperty
Known selectable properties
<MeetingProperty Select="InstanceID" /> returns 20100908
<MeetingProperty Select="MeetingCount" />
<MeetingProperty Select="StartTimeUTC" /> returns 20100908T073000Z
Method
More
PageUrl
ProjectProperty
ProjectedFields
Property
RightsChoices
RightsGroup
ScriptQuote
SelectionOptions
ServerProperty
SetList
SetVar
Switch
Text
Then
ThreadStamp
URL
UrlBaseName
UrlDirName
UserID
WebQueryInfo
Reference: View Schema Elements A-F G-L M-Z

Related

How to query fields with multiple values in Azure Cognitive Search

Working on Azure Cognitive Search with backend as MS SQL table, have some scenarios where need help to define a query.
Sample table structure and data :
Scenarios 1 : Need to define a query which will return data based on category.
I have tied query using search.ismatch but its uses prefix search and matches other categories as well with similar kind of values i.e. "Embedded" and "Embedded Vision"
$filter=Region eq 'AA' and search.ismatch('Embedded*','Category')
https://{AZ_RESOURCE_NAME}.search.windows.net/indexes/{INDEX_NAME}/docs?api-version=2020-06-30-Preview&$count=true&$filter=Region eq 'AA' and search.ismatch('Embedded*','Category')
And it will response with below result, where it include "Embedded" and "Embedded Vision" both categories.
But my expectation is to fetch data only if it match "Embedded" category, as highlighted below
Scenario 2: For the above Scenario 1, Need little enhancement to find records with multiple category
For example if I pass multiple categories (i.e. "Embedded" , "Automation") need below highlighted output
you'll need to use a different analyzer which will break the tokens on every ';' just for the category field rather than 'whitespaces'.
You should first ensure your Category data is populated as a Collection(Edm.String) in the index. See Supported Data Types in the official documentation. Each of your semicolon-separated values should be separate values in the collection, in a property called Category (or similar).
You can then filter by string values in the collection. See rules for filtering string collections. Assuming that your index contains a string collection field called Category, you can filter by categories containing Embedded like this:
Category/any(c: c eq 'Embedded')
You can filter by multiple values like this:
Category/any(c: search.in(c, 'Embedded, Automation'))
Start with clean data in your index using proper types for the data you have. This allows you to implement proper facets and you can utilize the syntax made specifically for this. Trying to work around this with wildcards is a hack that should be avoided.
To solve above mention problem used a below SQL function which will convert category to a json string array supported by Collection(Edm.String) data type in Azure Search.
Sql Function
CREATE FUNCTION dbo.GetCategoryAsArray
(
#ID VARCHAR(20)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #result NVARCHAR(MAX) = ''
SET #result = REPLACE(
STUFF(
(SELECT
','''+ TRIM(Value) + ''''
FROM dbo.TABLEA p
CROSS APPLY STRING_SPLIT (Category, ';')
WHERE p.ID = #ID
FOR XML PATH('')
),1,1,''),'&','&')
RETURN '[' + #result + ']'
END
GO
View to use function and return desired data
CREATE View dbo.TABLEA_VIEW AS
select
id
,dbo. GetCategoryAsArray(id) as CategoryArr
,type
,region
,Category
from dbo.TABLEA
Defined a new Azure Search Index using above SQL View as data source and during Index column mapping defined CategoryArr column as Collection(Edm.String) data type
Query to use to achieve expected output from Azure Search
$filter=Region eq 'AA' and CategoryArr/any(c: search.in(c, 'Embedded, Automation'))

Not able to see the label of the Api names

SelectedFields is the list of the fields having API Name and itr the iterative variable and similarly rec is the iterator variable for the records So whenever I am using {!itr}
in the facet then it will print API name and If do not use facet then it will print label of the fields how to fix this??
<apex:repeat value="{!selectedFields}" var="itr">
<apex:column value="{!rec[itr]}">
<apex:facet name="header">
<apex:commandLink action="{!sortByColumn}" reRender="recPage">{!itr}
<apex:param name="Names" value="{!itr}" assignTo="{!sortingValues}"/>
</apex:commandLink>
</apex:facet>
</apex:column>
Can you use $SobjectType to get the field label, something like {!$ObjectType.Account.fields[itr].label}?
Alternatively in apex build a Map<String, String> where key is the api name and value is the label. Or you can even iterate over list of field tokens, not strings. sObject class supports a dynamic get with field token as param so same trick should work in VF and you can get label out of a token too.
Yeah! {!$ObjectType.Account.fields[itr].label} It is the way to get the Label from the API name of Objects and For the dynamic objects. We can use this {!$ObjectType[sObject].fields[itr].label} as it will take out the label from the API names.

How to add Count() method on my content type in orchard?

I have a content type named "News" with Title, Body, Autoroute and a TextField. I have 2 problems:
To Count value of content items by text field named Author (can't use taxonomy terms).
To Count total sum of content items by Date (from 2017-01-01 to 2017-12-31)
Now, I want to add a Count() method on my content type, so I can filter, sort and use Projection.
How can I do this?
Or do you have a better method for it?
Thanks!
I'd use Orchards ISearchService for this. Just add your ContentType to a search index (you can have multiple indices) and check the fields you want to include, like created and author.
Then you can search like this and use the TotalItemCount property of the ISearchService:
var pager = new Pager(this.OrchardServices.WorkContext.CurrentSite, page, pageSize);
var searchSettingsPart = this.OrchardServices.WorkContext.CurrentSite.As<SearchSettingsPart>();
// Orchard.Search.Services.ISearchService
var searchHits = this.searchService.Search.Query(
searchText,
pager.Page,
pager.PageSize,
searchSettingsPart.FilterCulture,
searchSettingsPart.SearchIndex,
searchSettingsPart.GetSearchFields(searchSettingsPart.SearchIndex),
searchHit => searchHit);
var count = searchHits.TotalItemCount;
As far as the description of your ContentType goes, I think Orchard already provides all the necessary filters for a projection.
If you need something special you'd need to implement your own FilterProvider. The ContentTypesFilter is a good example on how to do this.

How to create a dataview In Sharepoint with data from a join query?

I have 3 Lists in Sharepoint.
I want to create a dataview that is a join of 3 tables.
Table1 is joined with Table2 on FieldA
Table 2 is joined to Table3 on FieldB
Table1 has duplicate values in FieldA so I need to only return one value to join with Table2.
In Access my query looks like this:
SELECT DISTINCT WRK_InputWorkOrders.WorkOrder, Production1.[Part Number], Production1.[Work Order], Production1.Location, StationItems.Station, Production1.Description, Production1.Revision, WRK_InputWorkOrders.Status
FROM StationItems INNER JOIN (WRK_InputWorkOrders INNER JOIN Production1 ON WRK_InputWorkOrders.WorkOrder = Production1.[Work Order]) ON StationItems.Item = Production1.[Part Number]
WHERE (((WRK_InputWorkOrders.Status)<>"closed"));
Is there a way to write sql-like queries for dataviews?
I have Sharepoint Designer 2007 and Access.
The goal is to get a report that a user can view in Internet Explorer.
I have tried using this method. But it returns duplicate records
I found this suggestion. It suggests using an XPath Filter
not(#yourvalue = preceding-sibling::dfs:YourRepeatingRowName/#yourvalue)
But wasn't able to get it to work. I don't know what to enter as YourRepeatingRowName
I found this link. Does anyone know if it can be used to perform such a join?
Your question is more of an ADO.NET question. Unfortunately ADO.NET doesn't have an easy way to do this, which is why companies like bamboo Solutions builds theirCross List Web Part:
http://store.bamboosolutions.com/pc-42-1-cross-list-web-part.aspx
Otherwise I would attempt to use LINQ to query the tables. You might have more luck doing that.
Here is an example of a JOIN query provided by MS (I only changed the first two DataTable lines to represent filling a DataTable with an SPListItemCollection object)
DataTable orders = spListCol1.ToDataTable();
DataTable details = spListCol2.ToDataTable();
var query =
from order in orders.AsEnumerable()
join detail in details.AsEnumerable()
on order.Field<int>("SalesOrderID") equals
detail.Field<int>("SalesOrderID")
where order.Field<bool>("OnlineOrderFlag") == true
&& order.Field<DateTime>("OrderDate").Month == 8
select new
{
SalesOrderID =
order.Field<int>("SalesOrderID"),
SalesOrderDetailID =
detail.Field<int>("SalesOrderDetailID"),
OrderDate =
order.Field<DateTime>("OrderDate"),
ProductID =
detail.Field<int>("ProductID")
};
DataTable orderTable = query.CopyToDataTable();
Microsoft has a video demo and a writeup that may be just what you want:
Display data from multiple sources in a single Data View
http://office.microsoft.com/en-us/sharepointdesigner/HA103511401033.aspx
With Microsoft Office SharePoint Designer 2007, you can link two or more data sources that contain related data and then create a single Data View that displays data from those linked data sources.
you want to show the query result in SharePoint Designer? I believe, SPD has merged data sources. Look into that.
I found this third part add on
Enesys RS Data Extension lets you query (retrieve, join, merge,...) data from any SharePoint list and use the result for building "Reporting Services" reports as you would do with any other data sources. http://www.enesyssoftware.com/
I can't use it because I am currently running the basic Sharepoint version that uses the internal database.
I've done something like this, but I wasn't able to use a dataview. I ended up writing a custom web part to do it. The approach was:
Use an SPQuery object to get an SPListItemCollection for each list. Use the CAML query to restrict the items returned.
Use the SPListItemCollection object's GetDataTable() method to retrieve an ADO.NET DataTable object for each list.
Add the tables to a DataSet object.
Create relationships between the tables.
Render the data however you like, using DataList or Repeater or whatever.
Here's some code that shows the broad strokes:
protected DataTable GetDataTableFromQuery(string camlQry, SPList theList) {
SPQuery listQry = new SPQuery();
listQry.Query = camlQry;
SPListItemCollection listItems = theList.GetItems(listQry);
return listItems.GetDataTable();
}
protected void BuildDataSet() {
// get SPList objects for the lists in questions ... left as an exercise for the dev -- call them list1, list2, and list3
string camlQry = "the CAML necessary to retreive the ites from list1";
DataTable table1 = GetDataTable(camlQry, list1);
table1.TableName = "Table1";
camlQry = "the CAML necessary to retreive the ites from list2";
DataTable table2 = GetDataTable(camlQry, list2);
table1.TableName = "Table2";
camlQry = "the CAML necessary to retreive the ites from list3";
DataTable table3 = GetDataTable(camlQry, list3);
table1.TableName = "Table3";
// now build the DataSet
DataSet ds = new DataSet();
ds.Tables.Add(table1);
ds.Tables.Add(table2);
ds.Tables.Add(table3);
ds.Relations.Add("Table1_2", ds.Tables["Table1"].Columns["FieldA"], ds.Tables["Table2"].Columns["FieldA"]);
ds.Relations.Add("Table2_3", ds.Tables["Table2"].Columns["FieldB"], ds.Tables["Table3"].Columns["FieldB"]);
// now you can do something with these, like store them in the web part class and bind them to repeaters in the web part's Render() method
}

What is the best way to retrieve distinct / unique values using SPQuery?

I have a list that looks like:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
Using CAML and the SPQuery object I need to get a distinct list of items from the Year column which will populate a drop down control.
Searching around there doesn't appear to be a way of doing this within the CAML query. I'm wondering how people have gone about achieving this?
Another way to do this is to use DataView.ToTable-Method - its first parameter is the one that makes the list distinct.
SPList movies = SPContext.Current.Web.Lists["Movies"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";
DataTable tempTbl = movies.GetItems(query).GetDataTable();
DataView v = new DataView(tempTbl);
String[] columns = {"Year"};
DataTable tbl = v.ToTable(true, columns);
You can then proceed using the DataTable tbl.
If you want to bind the distinct results to a DataSource of for example a Repeater and retain the actual item via the ItemDataBound events' e.Item.DataItem method, the DataTable way is not going to work. Instead, and besides also when not wanting to bind it to a DataSource, you could also use Linq to define the distinct values.
// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");
// Make sure the list was successfully retrieved
if(list == null) return;
// Retrieve all items in the list
var items = list.GetItems();
// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()
// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();
Remember that since there is no CAML support for distinct queries, each sample provided on this page will retrieve ALL items from the SPList. This may be fine for smaller lists, but for lists with thousands of listitems, this will seriously be a performance killer. Unfortunately there is no more optimized way of achieving the same.
There is no DISTINCT in CAML to populate your dropdown try using something like:
foreach (SPListItem listItem in listItems)
{
if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
{
ListItem ThisItem = new ListItem();
ThisItem.Text = listItem["Year"].ToString();
ThisItem.Value = listItem["Year"].ToString();
ddlYear.Items.Add(ThisItem);
}
}
Assumes your dropdown is called ddlYear.
Can you switch from SPQuery to SPSiteDataQuery? You should be able to, without any problems.
After that, you can use standard ado.net behaviour:
SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.
DataTable table = SPContext.Current.Web.GetSiteData(query);
//create a new dataview for our table
DataView view = new DataView(table);
//and finally create a new datatable with unique values on the columns specified
DataTable tableUnique = view.ToTable(true, "Year");
After coming across post after post about how this was impossible, I've finally found a way. This has been tested in SharePoint Online. Here's a function that will get you all unique values for a column. It just requires you to pass in the list Id, View Id, internal list name, and a callback function.
function getUniqueColumnValues(listid, viewid, column, _callback){
var uniqueVals = [];
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" }
}).then(function(response) {
$(response).find('OPTION').each(function(a,b){
if ($(b)[0].value) {
uniqueVals.push($(b)[0].value);
}
});
_callback(true,uniqueVals);
},function(){
_callback(false,"Error retrieving unique column values");
});
}
I was considering this problem earlier today, and the best solution I could think of uses the following algorithm (sorry, no code at the moment):
L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options
1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X
This would reduce the total number of items returned significantly, at the cost of making more queries.
It doesn't much matter if X is entirely accurate, but the randomness is quite important. Essentially the first query is likely to include the most common options, so the second query will exclude these and is likely to include the next most common options and so on through the iterations.
In the best case, the first query includes all the options, then the second query will be empty. (X items retrieved in total, over 2 queries)
In the worst case (e.g. the query is ordered by the options we're looking for, and there are more than X items with each option) we'll make as many queries as there are options. Returning approximately X * X items in total.

Resources