SQL Query CONTAINS property value in array of objects - azure

I am trying to create a SQL query to get a list of companies that a User belongs to. The database is Cosmos DB Serverless, and the container is called "Companies" with multiple company items inside:
The structure of the company items are as follows:
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Company Name",
"users": [
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Susan Washington",
"email": "susan.washington#gmail.com",
"createdBy": "xxxx#gmail.com",
"createdServerDateUTC": "2022-01-12T19:21:10.0644424Z",
"createdLocalTime": "2022-01-12T19:21:09Z"
},
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Kerwin Evans",
"title": "Test Dev",
"email": "kerwin.e#yahoo.com",
"createdBy": "xxxx#gmail.com",
"createdServerDateUTC": "2022-01-12T19:21:10.0644424Z",
"createdLocalTime": "2022-01-12T19:21:09Z"
},
ETC.
]
}
And this is the SQL query I was trying to use, where user is an email that I pass in:
SELECT *
FROM c
WHERE IS_NULL(c.deletedServerDateUTC) = true
AND CONTAINS(c.users, user)
ORDER BY c.name DESC
OFFSET 0 LIMIT 10
This doesn't work, because the users property is an array. So I believe I need to check each object in the users array to see if the email property matches the user I enter in.

You can query the array via ARRAY_CONTAINS(). Something like this to return company names for a given username that you specify:
SELECT c.name
FROM c
WHERE ARRAY_CONTAINS(c.users,{'name': username}, true)
The 3rd parameter set to true means the array elements are documents, not scalar values.

Related

How to get the user information using the user lookup ID from fields property when accessing items from a share-point list using Ms Graph API

I am accessing a Share-point list using the MS graph API endpoint:
https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items?expand=fields
I am getting the list items just fine, but I also want to get the user information attached in each field. The data item returned looks like this:
{
...other properties,
"fields": {
"#odata.etag": "\"eTag,1\"",
"id": "1",
"ContentType": "Item",
"Title": "<Some Title>",
"Modified": "<modified dateTime>",
"Created": "<created dateTime>",
"AuthorLookupId": "12",
"EditorLookupId": "12",
"_UIVersionString": "1.0",
"Attachments": false,
"Edit": "",
"LinkTitleNoMenu": "<num>",
"LinkTitle": "<num>",
"ItemChildCount": "0",
"FolderChildCount": "0",
"_ComplianceFlags": "",
"_ComplianceTag": "",
"_ComplianceTagWrittenTime": "",
"_ComplianceTagUserId": "",
"Status_Name": "<status_name>",
"Title0": "<some_title>",
"Dept": "Dept A",
"Emp_LeadLookupId": "200", //This is the user whose details I need(email-id)
"Quality_Approver": "<some_user>"
}
}
How do I get the user's details as well and not just a LookupId, OR how can I use the look up ID to get the said user's information?
I searched above and beyond but didn't find anything relevant. Any help is greatly appreciated!
Currently Microsoft Graph is not support the function of finding users through the lookup column.

i can't query over populated children attributes

I am trying to query over populated children attributes using mongoose but it straight up doesn't work and will return empty arrays all the time.
even hardcoding right and existing information as values for the query would return empty arrays.
my schema is a business schema with a 1 to 1 relationship with user schema via the attribute createdBy. the user schema has an attribute name which I am trying to query on.
so if I make a query like this :
business.find({'createdBy.name': {$regex:"steve"}}).populate('createdBy')
the above will never return any documents. although, without the find condition, everything works fine.
Can I search by the name inside a populated child or not? all tutorials say this should work fine but it just doesn't.
EDIT : an example of what the record looks like :
{
"_id": "5fddedd00e8a7e069085964f",
"status": 6,
"addInfo": "",
"descProduit": "",
"createdBy": {
"_id": "5f99b1bea9ba194dec3bd6aa",
"status": 1,
"fcmtokens": [
],
"emailVerified": 1,
"phoneVerified": 0,
"userType": "User",
"name": "steve buschemi",
"firstName": "steve",
"lastName": "buschemi",
"tel": "",
"email": "steve#buschemi.com",
"register_token": "747f1e1e8fa1ecd2f1797bb402563198",
"createdAt": "2020-10-28T18:00:30.814Z",
"updatedAt": "2020-12-18T13:52:07.430Z",
"__v": 19,
"business": "5f99b1e101bfff39a8259457",
"credit": 635,
},
"createdAt": "2020-12-19T12:10:57.703Z",
"updatedAt": "2020-12-19T12:11:16.538Z",
"__v": 0,
"nid": "187"
}
It seems there is no way to filter parent documents by conditions on child documents:
From the official documentation:
In general, there is no way to make populate() filter stories based on properties of the story's author. For example, the below query won't return any results, even though author is populated.
const story = await Story.
findOne({ 'author.name': 'Ian Fleming' }).
populate('author').
exec();
story; // null
If you want to filter stories by their author's name, you should use denormalization.

List iteration on python with mongodb

I am working on a small python project where I need to create a mongodb entry.
This is the list of values you received from another collection:
["India", "Australia", "South Africa"]
So the above list contains three items. What I want from my next collection is:
{
"_id": ObjectId('some id'),
"name": "Player",
"value": "India"
}
{
"_id": ObjectId('some id'),
"name": "Player",
"value": "Australia"
}
{
"_id": ObjectId('some id'),
"name": "Player",
"value": "South Africa"
}
I only want the list of values to be added in the value key but the name should be constant. It should repeat again and again but the value key will be changed based on number entries in the list.
How do I approach this problem in python?
You can apparoch this issue in different ways. A very basic one would be using list comprehensions like this:
values_list = ["India", "Australia", "South Africa"]
names_list = ["Peter", "Paul", "Mary"]
def create_objects(name, values):
# this returns a list of dicts basically and should be adopted to create 'real' mongoDB objects/entries
return [{"_id": "some id", "name": name, "value": value} for value in values]
objects = [create_objects(name, values_list) for name in names_list]
print(objects)
Another way is to calculate all possible combinations (called product in itertools) before-hand to prevent the two interating for-loops
from itertools import product
objects = [{"_id": "some id", "name": name, "value": value} for name, value in product(names_list, values_list)]
print(objects)

Azure Search match against two properties of the same object

I would like to do a query matches against two properties of the same item in a sub-collection.
Example:
[
{
"name": "Person 1",
"contacts": [
{ "type": "email", "value": "person.1#xpto.org" },
{ "type": "phone", "value": "555-12345" },
]
}
]
I would like to be able to search by emails than contain xpto.org but,
doing something like the following doesn't work:
search.ismatchscoring('email','contacts/type,','full','all') and search.ismatchscoring('/.*xpto.org/','contacts/value,','full','all')
instead, it will consider the condition in the context of the main object and objects like the following will also match:
[
{
"name": "Person 1",
"contacts": [
{ "type": "email", "value": "555-12345" },
{ "type": "phone", "value": "person.1#xpto.org" },
]
}
]
Is there any way around this without having an additional field that concatenates type and value?
Just saw the official doc. At this moment, there's no support for correlated search:
This happens because each clause applies to all values of its field in
the entire document, so there's no concept of a "current sub-document
https://learn.microsoft.com/en-us/azure/search/search-howto-complex-data-types
and https://learn.microsoft.com/en-us/azure/search/search-query-understand-collection-filters
The solution I've implemented was creating different collections per contact type.
This way I'm able to search directly in, lets say, the email collection without the need for correlated search. It might not be the solution for all cases but it works well in this case.

How to filter SharePoint list items by Created by in Microsoft Graph?

I'm trying to get a collection of list items from a SharePoint through Microsoft Graph, which I want to filter by CreatedBy.
Requesting: https://graph.microsoft.com/v1.0/sites/{siteid}/lists/TeamRequests/items
Returns:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('{url}')/lists('TeamRequests')/items",
"value": [
{
"#odata.etag": "\"56ad787e-bd69-464a-b5da-dd953e40d7c4,13\"",
"createdDateTime": "2018-02-26T08:34:26Z",
"eTag": "\"56ad787e-bd69-464a-b5da-dd953e40d7c4,13\"",
"id": "11",
"lastModifiedDateTime": "2018-03-22T13:20:03Z",
"webUrl": "{url}/Lists/TeamRequests/11_.000",
"createdBy": {
"user": {
"email": "{email}",
"id": "9c9cbb67-c049-4a2d-845d-6c5ca2300041",
"displayName": "{Name}"
}
},
"lastModifiedBy": {
"user": {
"email": "{email}",
"id": "9c9cbb67-c049-4a2d-845d-6c5ca2300041",
"displayName": "{Name}"
}
},
"parentReference": {},
"contentType": {
"id": "0x01005F15F8133495554D834FF82F187AD0630002133A9CCDE4494D8CB2206D7D6453D6"
}
},
Now I'd like to filter this request for createdBy, either Id, displayName or email address. I tried ?$filter=createdBy/user/email eq '{email}' and similar requests for id or displayName. They all return
{
"error": {
"code": "generalException",
"message": "An unspecified error has occurred.",
"innerError": {
"request-id": "492e3bde-05fe-4484-a475-435ff0aa70b6",
"date": "2018-07-23T07:41:46"
}
}
}
So how to accomplish this filter? Is it even supported?
Even though it sounds like a straightforward query, i have not come up to anything more simple then the following solution:
It seems filtering by user field is not supported except the case when user id is provided, that's the reason why the solution consists of two steps:
1) First, we need to determine user Id by Email , for that purpose the following query could be utilized:
https://graph.microsoft.com/v1.0/sites/root/lists('User Information List')/items?expand=fields(select=Id,Email)
*where User Information List system list stores user properties including Id and Email properties *
2) Once the user Id is resolved, the final query to filter items by user id could be applied:
https://graph.microsoft.com/v1.0/sites/{site-id}/lists('list-name')/items?filter=fields/<user-field-name>LookupId eq '<user-id>'
where
<user-field-name>LookupId is a field which is getting exposed in addition to user field, in case of Created field the name should be AuthorLookupId
Example:
https://graph.microsoft.com/v1.0/sites/root/lists('TeamRequests')/items?filter=fields/AuthorLookupId eq '10'
Note
In some cases the following error is returned Field ''
cannot be referenced in filter or orderby as it is not indexed.
Provide the 'Prefer: HonorNonIndexedQueriesWarningMayFailRandomly'
header to allow this, but be warned that such queries may fail on
large lists.
In that case the following request header needs to be applied:
Prefer: HonorNonIndexedQueriesWarningMayFailRandomly
When I tried to access User Information List list. There is an error with list not found.
So since in my case, first I filtered list data based on status value and next step got the logged in user display name and filtered listitems based on display name.
I'm using #pnp/graph
Filter list data with status filter
let resultsList = await listItemsQuery.filter("fields/RequestStatus eq 'Approval Pending'").expand("fields").get<MicrosoftGraph.ListItem[]>();
Get Logged-In Profile:
const profileQueryEndPoint = new GraphQueryableCollection(graph.me, "/");
Select displayName property from above result
let profileData : User = await profileQueryEndPoint.select("displayName").get <User>();
console.log('displayName : ' + profileData['displayName']);
Filter ListItems with createdby Field by passing profileData['displayName']
let filterUserCreatedRequests: MicrosoftGraph.ListItem[] = resultsList.filter(ListItem => ListItem["createdBy"].user.displayName === profileData['displayName']);
Display filtered results
console.log('filterUserCreatedRequests : ' + JSON.stringify(filterUserCreatedRequests));
I'm giving all the steps for your reference. But above code can simplified more.
Hope this helps someone :)

Resources