Azure CosmosDb stored procedure select query from string array - asp.net-core

I am writing an SP to delete some records. So i need to fetch the records which record ids are passed as string array.
function DeleteFn(email, docs) {
var container = getContext().getCollection();
var containerLink = container.getSelfLink();
var documentQuery =
{
'query': 'SELECT * FROM c where c.email = #email and ARRAY_CONTAINS(#arr, c.id) ',
'parameters': [{ 'name': '#email', 'value': email }, { 'name': '#arr', 'value': docs }]
};
container.queryDocuments(containerLink, documentQuery,
function (err, items) {
items.forEach(element => {
container.deleteDocument(element, {}, function (err, responseOptions) {
if (err) throw err;
});
});
}
});
}
where email = 'test#test.com' and docs = ["doc1","doc2"]
am getting parse error for JSON.Parse(docs).
How to execute this or any better approach to direct delete?

The first parameter of method deleteDocument should be documentLink. So you need to change your code to this:
container.deleteDocument(element._self, {}, function (err, responseOptions)
Then, if you pass your record ids as type String, you need to change your code like this:
'parameters' : [{'name':'#email', 'value':email}, { 'name': '#arr', 'value': JSON.parse(docs) }]
If you pass your record ids as type Custom, your code can work fine.
'parameters': [{ 'name': '#email', 'value': email }, { 'name': '#arr', 'value': docs }]

Related

Mapping raw sql result to graphql compatible structure in typeorm

post resolver fetches posts from postgres database and return them in response to graphql request.
The return value is array of Post entity objects. Post entity structure is given below.
{
id: 29,
title: 'Turkey Earthquake kills 1000 plus people',
text: "Body is saying and don't go to the dark path",
points: 0,
creatorId: 44,
createdAt: 2023-02-07T06:53:39.453Z,
updatedAt: 2023-02-08T07:01:54.409Z,
creator: User {
id: 44,
username: 'prashant',
email: 'prashant#gmail.com',
password: '$argon2id$v=19$m=65536,t=3,p=4$LqsF/Gb3E8J4+vm5TszyWQ$d+LhZ6mNOE4eLqWvdwItQ3qYMZr17+CfvPt9l0Iqk3M',
createdAt: 2023-02-06T07:32:11.717Z,
updatedAt: 2023-02-06T07:32:11.717Z
}
}
Now I have a subquery in SELECT section of the query.
#Query(() => PaginatedPosts)
async posts(
#Arg('limit', () => Int) limit: number,
#Arg('cursor', () => String, { nullable: true }) cursor: string | null,
#Ctx() { req, dataSource }: MyContext
): Promise<PaginatedPosts> {
const realLimit = Math.min(30, limit)
const realLimitPlusOne = realLimit + 1
const qb = dataSource
.createQueryBuilder()
.select('p')
.from(Post, 'p')
.innerJoinAndSelect('p.creator', 'u')
.orderBy('p.createdAt', 'DESC')
.take(realLimitPlusOne)
if (req.session.userId)
qb.addSelect((qb) => {
return qb
.subQuery()
.select('d.value')
.from(Updoot, 'd')
.where('"userId" = :userId AND "postId" = p.id', {
userId: req.session.userId
})
}, 'voteStatus')
else qb.addSelect('null', 'voteStatus')
if (cursor)
qb.where('p.createdAt < :cursor', {
cursor: new Date(parseInt(cursor))
})
const posts = await qb.getMany() // this is returning the above structure without `voteStatus` field in it.
console.log('posts: ', posts[0])
return {
posts: posts.slice(0, realLimit),
hasMore: posts.length === realLimitPlusOne
}
}
But instead of using await qb.getMany() if I use
const posts = await qb.getRawMany()
I get the data in following structure
{
p_id: 29,
p_title: 'Turkey Earthquake kills 1000 plus people',
p_text: "Body is saying and don't go to the dark path",
p_points: 0,
p_creatorId: 44,
p_createdAt: 2023-02-07T06:53:39.453Z,
p_updatedAt: 2023-02-08T07:01:54.409Z,
u_id: 44,
u_username: 'prashant',
u_email: 'prashant#gmail.com',
u_password: '$argon2id$v=19$m=65536,t=3,p=4$LqsF/Gb3E8J4+vm5TszyWQ$d+LhZ6mNOE4eLqWvdwItQ3qYMZr17+CfvPt9l0Iqk3M',
u_createdAt: 2023-02-06T07:32:11.717Z,
u_updatedAt: 2023-02-06T07:32:11.717Z,
voteStatus: -1
}
Which is not compatible with the graphql type I intend to respond with. So I am confused whether there is another way I can use queryBuilder to return the result with the compatible type or do I have to explicitly create a mapping function to map each object to desired structure of Post entity.

How to change the columns collection set of a kendo TreeList dynamically?

Try to change the columns list dynamically via a query ...
When I construct the TreeList, I call for columns :
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope)
If I return a simple array with the fields, it's working ..
If I call a $http.get (inside my getKPIColumnList(..) function) which add some columns to the existing array of columns, the TreeList is not constructed correctly.
Any suggestion will be really appreciated ! :)
EDIT 22-10-2019 09:00
Treelist init
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope),
scrollable: true,
columnMenu : {
columns : true
},
height: "100%",
dataBound: function (e) {
ExpandAll();
},
dataSource: {
schema: {
model: {
id: "id",
parentId: "parentId",
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: true },
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: false }
}
}
}
},
transport: {
read: {
url: "/api/AnalyseCenter/GetWorkOrderTree/0",
dataType: "json"
}
}
}
The getKPIColumnList return an static array + some push with dynamic columns (from DB)
angular.module('AnalyseCenterDirectives')
.service ('AnalyseCenterSKUService', function ($http) {
var toReturn = [ {field: "Name", title: "Hiérachie SKU", width: "30%" }, ..., ..., .... ];
I try in this function to push DB result
return $http.get("/api/AnalyseCenter/GetWorkOrderHistorianAdditonalColumns?equipmentName=" + equipmentName)
.then(function (result) {
var data = result.data;
if (data && data !== 'undefined') {
var fromDB = data;
angular.forEach(fromDB, function (tag) {
var tagName = tag.replace(".","_");
toReturn.push({
field: tagName, title: tag, width: '10%',
attributes: { style: "text-align:right;"} })
})
The stored procedure GetWorkOrderHistorianAdditonalColumns returns a list of string (future column)
That is because ajax is async, that means your tree list is being initialized before the request finishes. A classic question for JavaScript newcomers. I suggest you take a while to read about ajax, like How does AJAX works for instance.
Back to your problem. You need to create your tree list inside the success callback(I can't give you a more complete solution since I don't know what you're doing inside your function or which framework you're using to open that ajax request) with the result data, which is probably your columns. Then it would work as if you're initializing it with arrays.

How to loop through an array containing objects and do comparison

I am using ionic 4. I get the result from the API then get the result show like this
[
{"name":John,"age":20},
{"name":Peter,"age":35},
{"name":Alex,"age":15}
]
But I want to get the name only to check whether have same name with my condition or not. But I cannot straight a way get the result from the API, I need to hard code to do comparison. Here is my code:
this.http.get(SERVER_URL).subscribe((res) => {
const data = [
{ name: John, age: 21 },
{ name: Thomas, age: 25 },
];
const ppl= data.find(people=> people.name === 'alex');
console.log(ppl);
});
So, My first question is How to get the name from the API directly, not like now I hard code the result from API. My Second Question is when I do comparison I want to show the result 'already exist' or 'can use this name'. Because if I write my code like this I will get the error Type 'void' is not assignable to type 'boolean':
const ppl= data.find((people)=> {
if(people.name === 'alex') {
this.text = 'already exist'
} else {
this.text = 'can use this name'
}});
console.log(ppl);
Anyone can help me? Thank you very much
Instead of defining data, use the contents of the response; res will have the exact same contents that you are declaring in data.
this.http.get(SERVER_URL).subscribe(res => {
// If successful, res is an array with user data like the following
// [
// {name: "John", age: 21},
// {name: "Thomas", age: 25},
// ...
// ]
if (res.find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
});
Taken from the MDN docs on Array.prototype.find():
The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
In that case
res.find(user => user.name === 'alex')
will return a user object if any of the usernames match alex, or undefined if none of the user.name attributes match alex.
undefined evaluates to false and a user object evaluates to true in the conditional.
Keep in mind that you are comparing strings with ===, so, for example, Alex will not match alex, if you want to look into other ways to compare strings, have a look at this question.
You also might want to handle errors, how you handle them is up to you, and it will depend on the response, but you can access the error inside your subscribe like this:
this.http.get(SERVER_URL).subscribe(res => {
if (res.find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
}, error => {
console.log(error);
}, () => {
// There is also a 'complete' handler that triggers in both cases
});
Edit. API returns Object not array
If your API returns an Object instead of an array like in your question, you can still iterate over the properties
this.http.get(SERVER_URL).subscribe(res => {
// If successful, res is an array with user data like the following
// {
// key1: {name: "John", age: 21},
// key2: {name: "Thomas", age: 25},
// ...
// }
let match = false;
Object.keys(res).forEach(key => {
if (res[key].name === 'alex') {
match = true;
}
});
if (match) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}
});
Instead of Object.keys() you could use Object.values() to get an array with user objects, then use find() as before, but that seems less efficient, something like this:
if (Object.values(res).find(user => user.name === 'alex')) {
console.log ('Username has been taken');
} else {
console.log('Username is available');
}

How to chain get and map the result with lodash?

I've got a list I'm trying to pull an object from using _.get but following that selection I need to loop over the object to create a new property. So far I've been successful using a combination of _.get and _.map as shown below but I'm hoping I can use _.chain in some way.
var selected = _.get(results, selectedId);
return _.map([selected], result => {
var reviews = result.reviews.map(review => {
var reviewed = review.userId === authenticatedUserId;
return _.extend({}, review, {reviewed: reviewed});
});
return _.extend({}, result, {reviews: reviews});
})[0];
Is it possible to do a transform like this using something other than map (as map required me to break this up/ creating an array with a solo item inside it). Thank you in advance!
I can see that you're creating unnecessary map() calls, you can simply reduce all those work into something like this:
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
The defaults() method is similar to extend() except once a property is set, additional values of the same property are ignored.
var selectedId = 1;
var authenticatedUserId = 1;
var results = {
1: [
{ userId: 1, text: 'hello' },
{ userId: 2, text: 'hey' },
{ userId: 1, text: 'world?' },
{ userId: 2, text: 'nah' },
]
};
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
document.body.innerHTML = '<pre>' + JSON.stringify(output, 0, 4) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

How to get filtered rows from GridX?

I'm using Dojo GridX with many modules, including filter:
grid = new Grid({
cacheClass : Cache,
structure: structure,
store: store,
modules : [ Sort, ColumnResizer, Pagination, PaginationBar, CellWidget, GridEdit,
Filter, FilterBar, QuickFilter, HiddenColumns, HScroller ],
autoHeight : true, autoWidth: false,
paginationBarSizes: [25, 50, 100],
paginationBarPosition: 'top,bottom',
}, gridNode);
grid.filterBar.applyFilter({type: 'all', conditions: [
{colId: 'type', condition: 'equal', type: 'Text', value: 'car'}
]})
I've wanted to access the items, that are matching the filter that was set. I've travelled through grid property in DOM explorer, I've found many store references in many modules, but all of them contained all items.
Is it possible to find out what items are visible in grid because they are matching filter, or at least those that are visible on current page? If so, how to do that?
My solution is:
try {
var filterData = [];
var ids = grid.model._exts.clientFilter._ids;
for ( var i = 0; i < ids.length; ++i) {
var id = ids[i];
var item = grid.model.store.get(id);
filterData.push(item);
}
var store = new MemoryStore({
data : filterData
});
} catch (error) {
console.log("Filter is not set.");
}
I was able to obtain filtered gridX data rows using gridX Exporter. Add this Exporter module to your grid. This module does exports the filtered data. Then, convert CSV to Json. There are many CSV to Json conversion javasripts out there.
this.navResult.grid.exporter.toCSV(args).then(this.showResult, this.onError, null)
Based on AirG answer I have designed the following solution. Take into account that there are two cases, with or without filter and that you must be aware of the order of rows if you have applied some sort. At least this works for me.
var store = new Store({
idProperty: "idPeople", data: [
{ idPeople: 1, name: 'John', score: 130, city: 'New York', birthday: '31/02/1980' },
{ idPeople: 2, name: 'Alice', score: 123, city: 'Wáshington', birthday: '07/12/1984' },
{ idPeople: 3, name: 'Lee', score: 149, city: 'Shanghai', birthday: '8/10/1986' },
...
]
});
gridx = new GridX({
id: 'mygridx',
cacheClass: Cache,
store: store,
...
modules: [
...
{
moduleClass: Dod,
defaultShow: false,
useAnimation: true,
showExpando: true,
detailProvider: gridXDetailProvider
},
...
],
...
}, 'gridNode');
function gridXDetailProvider (grid, rowId, detailNode, rendered) {
gridXGetDetailContent(grid, rowId, detailNode);
rendered.callback();
return rendered;
}
function gridXGetDetailContent(grid, rowId, detailNode) {
if (grid.model._exts.clientFilter._ids === undefined || grid.model._exts.clientFilter._ids === 0) {
// No filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._cache._priority.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._cache._priority.indexOf(rowId)).item().idPeople;
} else {
// With filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().idPeople;
}
}
Hope that helps,
Santiago Horcajo
function getFilteredData() {
var filteredIds = grid.model._exts.clientFilter._ids;
return grid.store.data.filter(function(item) {
return filteredIds.indexOf(item.id) > -1;
});
}