Outlook API Filter by Subject line only returns 275 results - outlook-restapi

We have been having issues with the Outlook Mail API for a while now. There was a known bug where filtering by subject line would not return results and it was fixed.
We tried our implementation again, but are capped at 275 results every time. Below is an example of the code/query that we are running and you can see that the first 2 pages have nextLink for the next page but the third page stops at 75 results with no nextLink. We tested this on multiple accounts (all with 30,000+ emails) and different subject line queries and get 275 results every time.
search emails that contain 'a' in the subject
Request 1
{
"$select": "ReceivedDateTime",
"$search": "\"subject:(a)\"",
"$top": 100
}
Response
result.value.length: 100
result.#odata.nextLink: https://outlook.office.com/api/v2.0/Me/MailFolders/Inbox/Messages/?%24select=ReceivedDateTime&%24search=%22subject%3a(a)%22&%24top=100&%24skiptoken=MSZZVlF3ZWsxNmJHMU5hbEY1V2xNd2VFOVVWVFZNVkZFMVQxZFZkRmxVUW0xTlV6RnNXWHByZWs1RVNtbFpNa2t5V1dwQmJXTjZNSGhOUkVFOQ%3d%3d -- this is the token for retrieveing the next page
Request 2
{
"$select": "ReceivedDateTime",
"$search": "\"subject:(a)\"",
"$top": "100",
"$skiptoken": "MSZZVlF3ZWsxNmJHMU5hbEY1V2xNd2VFOVVWVFZNVkZFMVQxZFZkRmxVUW0xTlV6RnNXWHByZWs1RVNtbFpNa2t5V1dwQmJXTjZNSGhOUkVFOQ=="
}
Response
result.value.length: 100
result.#odata.nextLink:
https://outlook.office.com/api/v2.0/Me/MailFolders/Inbox/Messages/?%24select=ReceivedDateTime&%24search=%22subject%3a(a)%22&%24top=100&%24skiptoken=MSZZVlF3ZWsxNmJHMU5hbEY1V2xNd2VFOVVWVFZNVkZFMVQxZFZkRmxVUW0xTlV6RnNXWHByZWs1RVNtbFpNa2t5V1dwQmJXTjZNSGxOUkVFOQ%3d%3d
Request 3
{
"$select": "ReceivedDateTime",
"$search": "\"subject:(a)\"",
"$top": "100",
"$skiptoken": "MSZZVlF3ZWsxNmJHMU5hbEY1V2xNd2VFOVVWVFZNVkZFMVQxZFZkRmxVUW0xTlV6RnNXWHByZWs1RVNtbFpNa2t5V1dwQmJXTjZNSGxOUkVFOQ=="
}
Response
result.value.length: 75
result.#odata.nextLink: undefined -- no next page
Has anyone else encountered this issue/is there a workaround? Thanks!

The search component for the mailboxes is capping results at a lower level. You'll notice that you get similar results if you search with OWA's search bar, for example. The search team is taking feedback on this for consideration in future planning, so I encourage you to leave feedback on UserVoice. I've logged a work item to revisit this cap, but I can't make any promises :)

Related

NetSuite: Need to get value Of Landed Cost Category Line Field using Transaction Saved Search

I am trying to somewhat mimic NetSuite's Landed Cost feature using NetSuite's customization options (SuiteBuilder,SuiteScript etc.) and then further extend the functionality according to my requirements.
For this I need to in script, get value of "LANDED COST CATEGORY" line field of item sublist in the Transaction records (like Bill, Purchase Order etc.) using saved search.
But in a saved search I was unable to find any Column/scriptId which would give me value of LANDED COST CATEGORY line field. We ARE able to get this value using record.load().getValue() but I need this value from multiple transaction records and using this approach may cause performance issues. So, please can you tell how we can access this value using saved search.
I don't believe Netsuite exposes that field in saved searches at this time. This is the records browser in Netsuite listing all of the available search columns for Transaction searches. The internal id for that column is landedcostcategory, and that doesn't show up on the list.
However, if your goal is to get this information in SuiteScript, then you can use the 'N/query' module. Pull up one of your Purchase Orders, open the Javascript console (Ctrl+Shift+J) and try this:
require(['N/query'], (query) => {
const suiteqlQuery = `SELECT
transaction as transaction_id,
BUILTIN.DF(transaction) as transaction_name,
BUILTIN.DF(item) as item_name,
item as item_id,
landedcostcategory as landedcostcategory_id,
BUILTIN.DF(landedcostcategory) as landedcostcategory_name
FROM
transactionline
WHERE
transaction='<internal id of your PO here>'`;
const results = query.runSuiteQL({query: suiteqlQuery}).asMappedResults();
console.log(JSON.stringify(results, null, 2));
/*
Example output for results:
[
{
"transaction_id": "12345",
"transaction_name": "Purchase Order #PO123456",
"item_name": "My Favorite iPod",
"item_id": 1234,
"landedcostcategory_id": 1,
"landedcostcategory_name": "Duties & Tariffs"
}
]
*/
})

SAP UI5 to Implement "go to" specific page on the table

I am new to SAP UI5 development. Currently the table is using "growing" and "growingThreshhold", then users can click more to see data of next page. Since we have thousands of data in that table, it takes user time to click more and more again to load next page data. we try to implement a function, that user can enter the page number then click a button and go to the specific page.
<Table id="genTable" growing="true" growingThreshold="60" fixedLayout="false" selectionChange="onHandleSelectChange"
backgroundDesign="Solid" updateFinished="onHandleGeneratorQueueUpdateFinished">
Expected UI:
I added a bar then UI display is good.
<Bar design="SubHeader">
<contentMiddle>
<Input type="Number" id="pageNumber" width="50px"></Input>
<Button id="goToButton" text="Go to" type="Emphasized" press="onHandleGoTo"></Button>
</contentMiddle>
</Bar>
For the backend logic, I refer to below articles, but still doesn't work.
https://blogs.sap.com/2016/12/14/sapui5-pagination-in-sap.m-table-on-button-click-using-odata-service/
https://sapyard.com/advance-sapui5-19-pagination-in-table-control-with-top-and-skip-query-options/
I tried to use read, the it can get the data back from odata service, but the data can't be refreshed in the table.
oModel.read("/ViewQueueSet", {
urlParameters: {
"$top": top,
"$skip": count
},
filters: [new Filter("RoleCode", FilterOperator.EQ, "G")],
useBatch: true,
success: function (tdata) { //successful Read in the server
var json = new JSONModel();
json.setData(tdata);
that.getView().setModel(json,"sapmodel");
sap.ui.core.BusyIndicator.hide();
},
error: function () {
sap.ui.core.BusyIndicator.hide();
}
});
}
also tried to call bindItems
//that.getView().setModel(json,"sapmodel");
//oTable.setModel(json); //JSON is preferred data format
//oTable.bindItems("/results",that.oGenQueueTemplate);
that.getView().byId("genTable").setModel(json);
that.getView().byId("genTable").bindItems("/results",that.oGenQueueTemplate);
Another approach I tried is to use bindItems, it call send the request to odata service, but it doesn't add the parameter top and skip parameter.
oTable.bindItems({
path: "/ViewQueueSet",
model: "sapmodel",
filters: [new Filter("RoleCode", FilterOperator.EQ, "G")],
template: this.oGenQueueTemplate,
// urlParameters: {
// "$top": top,
// "$skip": count
// },
parameters: {
"$top": top,
"$skip": count
}
});
Anyone has any idea about how to implement this functionality?
before I go into detail, please consider using other controls and/or ux patterns. imagine having thousands or millions of elements in backend and user equests to scroll to page 9292929 => for a responsive table (sap.m.Table) you would need to load all elements up to that page. Maybe filtering or some completely different approach could be tha right one.
The correct way to do this is by getting the listbinding and ask it to load more elements. how to ask the binding, may depend on the type of binding as well.
oTable = ... // get a reference on table
oItemsBinding = oTable.getBinding("items");
oItemsBinding.getLength() // will give you total number of elements
oItemsBinding.isLengthFinal() // will tell you if the length is final
oItemsBinding.getCurrentContexts() // will give you array of all loaded contexts.
now a few words to length and the length being final. If you have a binding implementation that knows the total number of objects (e.g. json - since it loads all elements to client, or OData, if cont is implemented in backend) then getLength will tell you the total number of objects.
if the backend doesnt have the count feature implemented, the length becomes final once you reach the end of the list (backend gives you less elements than you require - e.g. top=10,skip=90 returns 10 elements => length 100, not final; top=10,skip=100 returns 4 elements => length=104 becomes final)
Now, you can have a look at various binding implementations. But be aware that there is a lot to consider (direction of growing - upwards/downwards), at least you dont need to think about filtering/sorting - as this is part of the binding.
There is a nice (private) feature in sap.m.Table (or in sap.m.ListBase, to be more precise), which is called GrowingEnablement. you can use it like this:
// dont forget if _oGrowingDelagate is not undefined or similar
oTable._oGrowingDelegate.requestNewPage()
this will load one more page => you could start from reading the implementation of this method if you want to load several pages in one go.
you could also do a simple trick:
// assume you have 20 elements per page (default)
// and want to get to 7th page (elements 121 - 140)
// ckecks for 7th page exists and 7th page not yet loaded are omitted
oTable.setGrowingThreshold(70) // half of 140, so following load will load second page => 71 to 140
oTable._oGrowingDelegate.requestNewPage() // this will load the second page 71 - 140
// once loading is finished (take care of asynchronity)
oItemsBinding.attachEventOnce("dataReceived", function(oEvent){
// reset the growing threshold to 20
oTable.setGrowingThreshold(20)
// scroll to first element of 7th page (index 120, since count starts from 0)
oTable.scrollToInex(120)
})

Issue of getting more items in List(Actions on google)

I am developing a shopping bot in that user will ask for the product and then i will be fetching the results from the database and the results will be more than 10 items. I know that the default items for the list is 10 items. My question here is how to add a more button at the end of the list so that i can load more of the items into the list.
for(var p=0;p<=countforchunk;p++)
{
items[p] = {
optionInfo: {
key: (p + 1).toString(),
synonyms: temparray[p],
},
title: temparray[p],
url: "https://www.google.com/imgres?imgurl=https%3A%2F%2Fcdn.pixabay.com%2Fphoto%2F2015%2F04%2F23%2F22%2F00%2Ftree-736885__340.jpg&imgrefurl=https%3A%2F%2Fpixabay.com%2Fimages%2Fsearch%2Fnature%2F&tbnid=_2JirDBiGzi3lM&vet=12ahUKEwi71YPNxdrnAhVJGbcAHVi_BdEQMygAegUIARCFAg..i&docid=Ba_eiczVaD9-zM&w=546&h=340&q=images&ved=2ahUKEwi71YPNxdrnAhVJGbcAHVi_BdEQMygAegUIARCFAg",
image: new Image({
url: imgarray1[p],
alt: imgarray1[p]
}),
}
conv.ask(new List({
title: 'Search Results',
items: items
}));
resolve();
}
Please help me out,
Thanks.
As far as I can tell - there is no technical limit of 10 items. If you put 12 items in a list, for example, it will show 12 items.
This is not, however, a very good idea. (Even 10 items is a lot, and you should be thinking about voice interaction, where you might not want to read back more than 2 or 3). So at some point you will want to think about paging anyway.
If you do, you need to implement this as another Intent and Intent Handler. You can do this by offering a suggestion chip that says "Show me more" and accepting training phrases such as "more", "what else", and "show me more" in the Intent. You can use a Context to keep track of where you are in the result list.
You have to keep track of loaded item. There is limitation of loading 30 items at a time.
When user wants more item, you have handle that voice intent and can store current page index in context and based on that you can add another 30 items by replacing existing one.
1-30 items = page 1
30-60 items = page 2 and so on.
Call an api accordingly.

TYPO3: Performance issue with pagination

I am currently building some kind of video channel based on an extension I created. It consists of videos and playlist that contains videos (obviously).
I have to create a page which contains a list of videos AND playlist by category. You also can sort those items by date. Finally, the page is paginated with an infinite scrolling that should load items 21 by 21.
To do so, I created on both Video and Playlist repositories a "findByCategory" function which is really simple :
$query = $this->createQuery();
return $query->matching($query->equals('categorie.uid',$categoryUid))->execute()->toArray();
Once I requested the items I need, I merge them in one array and do my sorting stuff. Here is my controller show action :
if ($this->request->hasArgument('sort'))
$sort = $this->request->getArgument('sort');
else
$sort = 'antechrono';
//Get videos in repositories
$videos = $this->videoRepository->findByCategorie($categorie->getUid());
$playlists = $this->playlistRepository->findByCategorie($categorie->getUid());
//Merging arrays then sort it
if ($videos && $playlists)
$result = array_merge($videos, $playlists);
else if ($videos)
$result = $videos;
else if ($playlists)
$result = $playlists;
if ($sort == "chrono")
usort($result, array($this, "sortChrono"));
else if ($sort == "antechrono" || $sort == null)
{
usort($result, array($this, "sortAnteChrono"));
$sort="antechrono";
}
$this->view->assignMultiple(array('categorie' => $categorie, 'list' => $result, 'sort' => $sort));
Here is my view :
<f:widget.paginate objects="{list}" as="paginatedList" configuration="{addQueryString: 'true', addQueryStringMethod: 'GET,POST', itemsPerPage: 21}">
<div class="videos row">
<f:for each="{paginatedList}" as="element">
<f:render partial="Show/ItemCat" arguments="{item: element}"/>
</f:for>
</div>
</f:widget.paginate>
The partial render shows stuff including a picture used as a cover. So I need at least this relation in the view.
This works fine and shows only the items from the category that is requested. Unfortunatly I have a huge performance issue : I tried to show a category that contains more than 3000 records and It takes about one minute to load. It's a little bit long.
By f:debugging my list variable, I see that it contains every records even through it shouldn't be the case (that's the point of pagination...). So the first question is : is there something wrong in the way I did my pagination ?
I tried to simplify my requests by enabling the rawQuery thing ($query->execute(true)) : I get way better performance, but I can't get the link for the pictures (in my view, I get 1 or 0 but not the picture's uid...). Second question : is there a way to fix this issue ?
I hope my description is clear enough. Thanks for your help :-)
When you execute a query, it will not actually fetch the data from the database until the results are accessed. If the paginate widget gets a query result it will add limits and offset to the query and then fetch the data from the database, so you will only get the records that are shown on a page.
In your case you added toArray() after execute(), which accesses the results, so the data is fetched from the database and you get all records. The best solution I can think of is to combine the 2 tables into 1 so you can do it with a single query and don't have to merge and order them in PHP.
As long as you sort the data after the query you have to handle all data (request all records and especially resolve all relations).
Try to sort the data in the query itself (order by), so you could restrict the data to only those records which are needed for the current 'page' (limit <offset>,<number>).
Here a complex query with join and limit could be faster than a full query and filtering in PHP.

Cloudant 1 to many function

I’ve just started to use Cloudant and I just can’t get my head around the map functions. I’ve been fiddling with the data below but it isn’t working out as I expected.
The relationship is, a user can have many vehicles. A vehicle belongs to 1 user. The vehicle ‘userId’ is the key of the user. There is a bit of redundancy as in user the _id and userId is the same, guess later is not required.
Anyhow, how can I find for a/every user, the vehicles which belong to it? The closest I’ve come through trial and error is a result which displays the owner of every vehicle, but I would like it the other way round, the user and the vehicles belonging to it. All the examples I’ve found use another document which ‘joins’ two or more documents, but I don’t need to do that?
Any point in the right direction appreciated - I really have no idea.
function (doc) {
if (doc.$doctype == "vehicle")
{
emit(doc.userId, {_id: doc.userId});
}
}
EDIT: Getting closer. I'm not sure exactly what I was expecting, but the result seems a bit 'messy'. Row[0] is the user document, row[n > 0] are the vehicle documents. I guess it's fine when a startkey/endkey is used, but without the results are a bit jumbled up.
function (doc) {
if (doc.$doctype == 'user') {
emit([doc._id, 0], doc);
} else if (doc.$doctype == 'vehicle') {
emit([doc.userId, 1, doc._id], doc);
}
}
A user is described as,
{
"_id": "user:10",
"firstname": “firstnamehere",
"secondname": “secondnamehere",
"userId": "user:10",
"$doctype": "user"
}
a vehicle is described as,
{
"_id": "vehicle:4002”,
“name”: “avehicle”,
"userId": "user:10",
"$doctype": "vehicle",
}
You're getting in the right direction! You already got that right with the global IDs. Having the type of the document as part of the ID in some form is a very good idea, so that you don't get confused later (all documents are in the same "pot").
Here are some minor problems with your current solution (before getting to your actual question):
Don't emit the doc as value in emit(key, value). You can always ask for the document that belongs to a view row by querying with include_docs=true. Having the doc as view value increases the view indexes a lot. When you don't need a specific value, use emit(key, null).
You also don't need the ID in the emit value. You'll get the ID of the document that belongs to a view row as part of the row anyway.
View Collation
Now to your problem of aggregating the vehicles with their user. You got the basic pattern right. This pattern is called view collation, you can read more about it in the CouchDB docs (ignore that it is in the "Couchapp" section).
The trick with view collation is that you return two or more types of documents, but make sure that they are sorted in a way that allows for direct grouping. Thus it is important to understand how CouchDB sorts the view result. See the collation specification for more information on that one. An important key to understanding view collation is that rows with array keys are sorted by key elements. So when two rows have the same key[0], they sort by key[1]. If that's equal as well, key[2] is considered, and so on.
Your map function frist groups users and vehicles by user ID (key[0]). Your map function then uses the fact that 0 sorts before 1 in the second element of the key, so your view will contain the following:
user 1
vehicle of user 1
vehicle of user 1
vehicle of user 1
user 2
user 3
vehicle of user 3
user 4
etc.
As you can see, the vehicles of a user immediately follow their user. Thus you can group this result into aggregates without performing expensive sort or lookup operations.
Note that users are sorted according to their ID, and vehicles within users also according to their ID. This is because you use the IDs in the key array.
Creating Queries
Now that view isn't worth much if you can't query according to your needs. A view as you have it supports the following queries:
Get all users with their vehicles
Get a range of users with their vehicles
Get a single user with its vehicles
Get a single user without vehicles (you could also use the _all_docs view for that though)
Example query for "all users between user 1 and user 3 (inclusive) with their vehicles"
We want to query for a range, so we use startkey and endkey in the query:
startkey=["user:1", 0]
endkey=["user:3", 1, {}]
Note the use of {} as sentinel value, which is required so that the end key is larger than any row that has a key of ["user:3", 1, (anyConceivableVehicleId)]

Resources