I am using the Google Client library for PHP to fetch data from Google Analytics using Google Analytics Reporting API version 4. The issue is that it is not accepting my regular expression. I have confirmed that the regular expression works in Google's Query Explorer. It is when I try to use it with the Google_Service_AnalyticsReporting_DimensionFilter() class that it does not work. The output shows Totals equals zero meaning that no records were returned. Please take a look at the code below:
function getReport($analytics)
{
// Replace with your view ID, for example XXXX.
$VIEW_ID = $this->viewId;
// Create the DateRange object.
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate($this->startDate);
$dateRange->setEndDate($this->endDate);
// Create the Metrics object.
$sessions = new Google_Service_AnalyticsReporting_Metric();
$sessions->setExpression($this->metrics);
$sessions->setAlias($this->metricAlias);
//Create the Dimensions object.
$pagePath = new Google_Service_AnalyticsReporting_Dimension();
$pagePath->setName("ga:pagePath");
// Create Dimension Filter 1, Must use: =~
$dimensionFilter1 = new Google_Service_AnalyticsReporting_DimensionFilter();
$dimensionFilter1->setDimensionName("ga:pagePath");
$dimensionFilter1->setOperator('REGEXP');
$dimensionFilter1->setExpressions('27-of-the-most-beautiful-small-towns-to-visit-in-europe');
$dimensionFilter1->setNot(FALSE);
// Create Dimension Filter 2, Must use: !~
$dimensionFilter2 = new Google_Service_AnalyticsReporting_DimensionFilter();
$dimensionFilter2->setDimensionName("ga:pagePath");
$dimensionFilter2->setOperator('REGEXP');
$dimensionFilter2->setExpressions('\/.*?\/[0-9]+');
$dimensionFilter2->setNot(TRUE);
// Create Dimension Filter 3, Must use !~
$dimensionFilter3 = new Google_Service_AnalyticsReporting_DimensionFilter();
$dimensionFilter3->setDimensionName("ga:pagePath");
$dimensionFilter3->setOperator('REGEXP');
$dimensionFilter3->setExpressions('\/.*?\/images/images');
$dimensionFilter3->setNot(TRUE);
// Create the DimensionFilterClauses
$dimensionFilterClause = new Google_Service_AnalyticsReporting_DimensionFilterClause();
$dimensionFilterClause->setFilters([$dimensionFilter1, $dimensionFilter2, $dimensionFilter3]);
// Create the ReportRequest object.
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges($dateRange);
$request->setMetrics([$sessions]);
$request->setDimensions([$pagePath]);
$request->setDimensionFilterClauses([$dimensionFilterClause]);
$request->setIncludeEmptyRows(false);
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests([$request]);
return $analytics->reports->batchGet($body);
}
Is this code not correct?
// Create Dimension Filter 1.
$dimensionFilter = new Google_Service_AnalyticsReporting_DimensionFilter();
$dimensionFilter->setDimensionName("ga:pagePath");
$dimensionFilter->setOperator('REGEXP');
$dimensionFilter->setExpressions('ga:PagePath !~ \/.*?\/[0-9]+');
Yes. There is mistake in code. You should not include dimension name i.e. ga:pagePath in setExpression method.
I assume you are trying to add Does not match Regular Expression operator in filter.
So your code should be like this:
$dimensionFilter = new Google_Service_AnalyticsReporting_DimensionFilter();
$dimensionFilter->setDimensionName("ga:pagePath");
$dimensionFilter->setOperator('REGEXP');
$dimensionFilter->setExpressions('\/.*?\/[0-9]+');
$dimensionFilter->setNot(TRUE);
See whether it works or not.
Related
This is screenshot from analytics report:
Analytics Report Image
When I try to use google analytics report php api (v.2.2.2) with the filter event Category (filtered by "Videos" category):
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("3daysago");
$dateRange->setEndDate("today");
// Create the Metrics object.
$ev = new Google_Service_AnalyticsReporting_Metric();
$ev->setExpression("ga:eventValue");
$ev->setAlias("EventValue");
$tEv = new Google_Service_AnalyticsReporting_Metric();
$tEv->setExpression("ga:totalEvents");
$tEv->setAlias("Total Events");
$avg = new Google_Service_AnalyticsReporting_Metric();
$avg->setExpression("ga:avgEventValue");
$avg->setAlias("Avg Value");
//Create the dimensions
// $sc = new Google_Service_AnalyticsReporting_Dimension();
// $sc->setName("ga:subContinent");
$ec = new Google_Service_AnalyticsReporting_Dimension();
$ec->setName("ga:eventCategory");
$ea = new Google_Service_AnalyticsReporting_Dimension();
$ea->setName("ga:eventAction");
$el = new Google_Service_AnalyticsReporting_Dimension();
$el->setName("ga:eventLabel");
// Create the segment dimension.
$segmentDimensions = new Google_Service_AnalyticsReporting_Dimension();
$segmentDimensions->setName("ga:segment");
// Create Dimension Filter.
$dimensionFilter = new Google_Service_AnalyticsReporting_SegmentDimensionFilter();
$dimensionFilter->setDimensionName("ga:eventCategory");
$dimensionFilter->setOperator("EXACT");
$dimensionFilter->setExpressions(array("Videos"));
// Create Segment Filter Clause.
$segmentFilterClause = new Google_Service_AnalyticsReporting_SegmentFilterClause();
$segmentFilterClause->setDimensionFilter($dimensionFilter);
// Create the Or Filters for Segment.
$orFiltersForSegment = new Google_Service_AnalyticsReporting_OrFiltersForSegment();
$orFiltersForSegment->setSegmentFilterClauses(array($segmentFilterClause));
// Create the Simple Segment.
$simpleSegment = new Google_Service_AnalyticsReporting_SimpleSegment();
$simpleSegment->setOrFiltersForSegment(array($orFiltersForSegment));
// Create the Segment Filters.
$segmentFilter = new Google_Service_AnalyticsReporting_SegmentFilter();
$segmentFilter->setSimpleSegment($simpleSegment);
// Create the Segment Definition.
$segmentDefinition = new Google_Service_AnalyticsReporting_SegmentDefinition();
$segmentDefinition->setSegmentFilters(array($segmentFilter));
// Create the Dynamic Segment.
$dynamicSegment = new Google_Service_AnalyticsReporting_DynamicSegment();
$dynamicSegment->setSessionSegment($segmentDefinition);
$dynamicSegment->setName("Video");
// Create the Segments object.
$segment = new Google_Service_AnalyticsReporting_Segment();
$segment->setDynamicSegment($dynamicSegment);
// Create the ReportRequest object.
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges(array($dateRange));
$request->setSegments(array($segment));
$request->setDimensions(array($segmentDimensions,$ec,$ea,$el));
$request->setMetrics(array($ev, $avg, $tEv));
// Create the GetReportsRequest object.
$getReport = new Google_Service_AnalyticsReporting_GetReportsRequest();
$getReport->setReportRequests(array($request));
// Call the batchGet method.
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request) );
$response = $analyticsreporting->reports->batchGet( $body );
printResults($response->getReports());
And the result return all categories (Banner and Videos):
ga:segment: Video
ga:eventCategory: Banner
ga:eventAction: click
ga:eventLabel: click on banner
EventValue: 0
Avg Value: 0.0
Total Events: 52
----------------------------
ga:segment: Video
ga:eventCategory: Videos
ga:eventAction: play
ga:eventLabel: Fall Campaign
EventValue: 0
Avg Value: 0.0
Total Events: 29
I'm a beginer on this, can you show me what's my problem?
./Thanks
You seem to be creating a segment not a filter. You want to change your code to use Filters instead. Filters will only show you the data that matches the filter, while a segment will create a slice of all GA sessions that had at least one event with category Video. If other events were also present in the same sessions they would be included in the segment.
A good way to think about it is that segments only filter whole sessions and Filters can slice the actual returned data for the specific API call.
I have a Google drive table data source which stores list of open positions. Now in the data source I've set "Query per size" field to 10 so that I can get 10 records per page. I've added a Pager as well to show pagination.
My query is I want to display like "Page 1 of X" to my end users and this X will vary based on certain search filters. What will the best way to achieve this in Appmaker?
I've tried counting total records in a data source as per below code but every time updating that with the search criteria and recounting it is not a proper solution.
//Server side
var newQuery = app.models.Company.newQuery();
var records = newQuery.run();
var totalCount =0;
for(var i=0;i<records.length;i++)
{
totalCount=totalCount+1;
}
return totalCount;
In case you don't have any filters in your table your server code can be as simple as
// Server script
function getPagesCount(pageSize) {
var recordsCount = app.models.MyModel.newQuery().run().length;
var pagesCount = Math.ceil(recordsCount / pageSize);
return pagesCount;
}
As an alternative you can consider creating Calculated Model with a single field PagesCount.
In case you have some filters associated with the table then you'll need to run the query for the pages number with exact same filters.
Most likely the entire setup will not work effectively with Drive Tables since there is no way to query records number without querying records themselves. With Cloud SQL data backend one can create Calculated SQL Model with lightweight native SQL query (here :PageSize is query parameter which should be equal to the query.limit of the actual datasource):
SELECT
Ceil(COUNT(1) / :PageSize) AS RecordsNumber
FROM
TableName
WHERE
...
I've achieved this using Calculated Model as suggested by Pavel.
Steps :
Create a calculated data source with one field count.
In that data source add one parameter searchQuery. This will contain users filter going forward. Currently I have only one search query in which user can search many things. So I've added one parameter only.
In this data source add following server script.
Code:
// Server script
function getTotalRecords(query) {
var receivedQuery = query.parameters.searchQuery;
// console.log('Received query:' + query.parameters.searchQuery);
var records = app.models.Company.newQuery();
records.parameters.SearchText = query.parameters.searchQuery;
if(receivedQuery !== null) {
records.where = '(Name contains? :SearchText or InternalId contains? ' +
':SearchText or LocationList contains? :SearchText )';
}
var recordsCount = records.run().length;
var calculatedModelRecords = [];
var draftRecord = app.models.RecordCount.newRecord();
draftRecord.count = ''+recordsCount;
calculatedModelRecords.push(draftRecord);
return calculatedModelRecords;
}
.
On the Appmaker page bind a label with this data source.
On search query/your filter applied event add following code which Reload this data source and assign value to Parameter.
// Client script
function updateRecordCount(newValue) {
var ds = app.datasources.RecordCount;
ds.query.parameters.searchQuery = newValue;
ds.unload();
ds.load();
}
I'm trying to use a Segment Dimension Filter for a custom Dimension in the Google Analytics Api v4 in Java. As Template I am using the following Sample:
https://developers.google.com/analytics/devguides/reporting/core/v4/samples
This works fine with all Dimensions, but as soon as I try to filter one of our Custom Dimensions the Filter seems to stop working. It doesn't matter if the Dimension fulfills the filter-condition, the response includes all Values.
But the strange part is when I set a Value in the filter-condition that doesn't exists in the custom Dimension, I don't get any response. So in that moment the Filters seems to work.
Thank you all for your help.
// Create the DateRange object.
DateRange dateRange = new DateRange();
dateRange.setStartDate("yesterday");
dateRange.setEndDate("yesterday");
Metric User = new Metric().setExpression("ga:users").setAlias("User");
Dimension prev_page_path = new Dimension().setName("ga:previousPagePath");
Dimension err = new Dimension().setName("ga:dimension14");
Dimension ShopName = new Dimension().setName("ga:dimension1");
// Create the segment dimension.
Dimension segmentDimensions = new Dimension().setName("ga:segment");
// Create Dimension Filter.
SegmentDimensionFilter dimensionFilter = new SegmentDimensionFilter()
.setDimensionName("ga:dimension14")
.setOperator("EXACT")
.setExpressions(Arrays.asList("404"));
// Create Segment Filter Clause.
SegmentFilterClause segmentFilterClause = new SegmentFilterClause()
.setDimensionFilter(dimensionFilter);
// Create the Or Filters for Segment.
OrFiltersForSegment orFiltersForSegment = new OrFiltersForSegment()
.setSegmentFilterClauses(Arrays.asList(segmentFilterClause));
// Create the Simple Segment.
SimpleSegment simpleSegment = new SimpleSegment()
.setOrFiltersForSegment(Arrays.asList(orFiltersForSegment));
// Create the Segment Filters.
SegmentFilter segmentFilter = new SegmentFilter()
.setSimpleSegment(simpleSegment);
// Create the Segment Definition.
SegmentDefinition segmentDefinition = new SegmentDefinition()
.setSegmentFilters(Arrays.asList(segmentFilter));
// Create the Dynamic Segment.
DynamicSegment dynamicSegment = new DynamicSegment()
.setSessionSegment(segmentDefinition)
.setName("404");
// Create the Segments object.
Segment segment = new Segment()
.setDynamicSegment(dynamicSegment);
// Create the ReportRequest object.
ReportRequest request = new ReportRequest()
.setViewId(VIEW_ID)
.setDateRanges(Arrays.asList(dateRange))
.setDimensions(Arrays.asList( prev_page_path, ShopName, err, segmentDimensions))
.setSegments(Arrays.asList(segment))
.setMetrics(Arrays.asList(User));
// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest()
.setReportRequests(Arrays.asList(request));
// Call the batchGet method.
GetReportsResponse response = service.reports().batchGet(getReport).execute();
The Anwser would look like:
ga:previousPagePath: #########
ga:dimension1: #########
ga:dimension14: 404
ga:segment: 404
Date Range (0): User: 1
ga:previousPagePath: #########
ga:dimension1: #########
ga:dimension14: productlist
ga:segment: 404
Date Range (0): User: 1
...
The Problem still exists, but I found a Workaround, for everyone who is in the same Situation:
DimensionFilterClause DFC = new DimensionFilterClause().setFilters(Arrays.asList(
new DimensionFilter()
.setDimensionName("ga:dimension14")
.setOperator("EXACT")
.setExpressions(Arrays.asList("404"))));
// Create the ReportRequest object.
ReportRequest request = new ReportRequest()
.setViewId(VIEW_ID)
.setDateRanges(Arrays.asList(dateRange))
.setDimensionFilterClauses(Arrays.asList(DFC))
.setDimensions(Arrays.asList( prev_page_path, ShopName, Seitentyp))
.setMetrics(Arrays.asList(User));
I need help with trying to understand how to delete all data from a table and then try to automatically import a new sheet with data into the newly cleared down table.
I'm currently trying the unload() method client side but that doesn't seem to cleardown my tables
function ClearDown(){
app.datasources.P11d.unload(function(){});
console.log('Finish Delete');
}
I've also tried to create a server side function, which also doesn't appear to work
function ClearTable(){
var records = app.models.P11d.newQuery();
// records.run();
console.log('Server Function Ran');
app.deleteRecords(records.run());
}
This is ran from a client side function:
function Delete(){
google.script.run.withSuccessHandler(function(result){
}).ClearTable();
console.log('Function Ran');
}
Again this is all to no avail
With the import side I've tried to do the below:-
Client Side:
function ImportData(){
console.log('Begin');
var ss = SpreadsheetApp.openById('SHEET ID');
var values = ss.getSheetByName('P11d').getDataRange().getValues();
var ssData = [];
// app.datasources.P11d.unload(function(){});
for (var i = 0; i<values.length; i++){
var newRecord = app.models.P11d.newRecord();
// add all fields to the new record
newRecord.Reg_Number = values[i][0];
newRecord.Reg_Date = values[i][1];
newRecord.Model_Description = values[i][2];
newRecord.P11d_Value = values[i][3];
newRecord.EngineSize = values[i][4];
newRecord.Fuel = values[i][5];
newRecord.CO2 = values[i][6];
newRecord.SIPP = values[i][7];
newRecord.GTA_Code = values[i][8];
newRecord.Type = values[i][9];
ssData.push(newRecord);
// console.log(newRecord.MODEL_FIELD);
}
console.log('Finished');
// return the array of the model.newRecord objects that would be consumed by the Model query.
}
Please can someone help with this, at the moment the way the data is sent over to me adding new stuff into the Drive Table is causing many duplicates.
Thanks in advance,
You can delete all records, import, and read from a spreadsheet using the AMU Library
Copy and paste the server and client scripts into your app.
I'm sure that will make it much easier!
To delete all the data in a model using this:
Button onClick:
google.script.run.AMU.deleteAllData('ModelName');
The correct way to delete records on the server is:
app.models.MODEL_NAME.deleteRecords(key_array);
datasource.unload() simply unloads the widget on the client. It does not affect the database records.
A better way to write your records query on the server is:
var query = app.models.MODEL_NAME.newQuery();
query.filters.your_filter_here;
var records = query.run();
Note that you cannot return a single record or an array of records from anything but a calculated model function without using a function posted here. (You can return a single field of a record using stringify for any json data.)
I am currently working on a solution to create datasource independent tables needed in App Maker.
For the delete function on the server try to change your code just a little bit, this function at least used to work for me, however I have not needed to use it in some time.
function ClearTable(){
var records = app.models.P11d.newQuery().run();
console.log('Server Function Ran');
app.deleteRecords(records);
}
Hoping someone here can help me, I have the below code:
function getSSData(){
var values = SpreadsheetApp.openById('1iKO7j_ETu_x1iJf7y_ih76sDTBS21JULid_5pNIit8w').getSheets()[0].getDataRange().getValues();
var ssData = [];
// app.datasources.P11d.unload(function(){});
console.log('Made it to Line 5');
for (var i = 0; i<values.length; i++){
var newRecord = app.models.P11d.newRecord();
// add all fields to the new record
console.log('Made it to Line 9');
newRecord.MODEL_FIELD = values[i][0];
ssData.push(newRecord);
// console.log(newRecord.MODEL_FIELD);
}
console.log('Finished');
// return the array of the model.newRecord objects that would be consumed by the Model query.
return ssData;
}
I have taken this from another post on here, however I can't seem to understand what is happening around the MODEL_FIELD section. Do I need to specify each column title individually or will this just know what to do?
Thank you in advance and I'm sorry if the question seems simple, I'm still very new at this and trying to pick it up as I go along.
values is a 2d array of all of the data in your sheet.
Effectively, the code iterates over all of the rows retrieved from the sheet. For each row a new record is created and the value in the first column of each row is assigned to the field MODEL_FIELD in the new record.
Each new record is pushed into another array which is returned to the caller to be saved with app.saveRecords();