Finding record which doesn't contain some value in array fields - sql

I am using sequelize + typescript over node (with postgresql db) and I have the following model:
id: number,
someField: string,
arr1: number[],
arr2: number[]
and I'm trying to find all records in which arr1 and arr2 don't contain a certain value.
As far as I've seen my only option in one query is a mix between Op.not and Op.contains,
so I've tried the following queries:
/// Number 1
where: {
arr1: {
[Op.not] : {[Op.contains]: [someValue]}
},
arr2: {
[Op.not] : {[Op.contains]: [soemValue]}
}
},
/// Number 2
where: {
[Op.not]: [
{arr1: {[Op.contains]: [someValue]}},
{arr2: {[Op.contains]: [someValue]}}
]
},
Now, number 1 does compile in typescript but when trying to run it the following error returns:
{
"errorId": "db.failure",
"message": "Database error occurred",
"innerError":
{
"name": "SequelizeValidationError",
"errors":
[
{
"message": "{} is not a valid array",
"type": "Validation error",
"path": "arr1",
"value": {},
"origin": "FUNCTION",
"instance": null,
"validatorKey": "ARRAY validator",
"validatorName": null,
"validatorArgs": []
}
]
}
}
So I tried number 2, which didn't compile at all with the following TS error:
Type '{ [Op.not]: ({ arr1: { [Op.contains]: [number]; }; } | { arr2: { [Op.contains]: [number]; }; })[]; }' is not assignable to type 'WhereOptions<any>'.
Types of property '[Op.not]' are incompatible.
Type '({ arr1: { [Op.contains]: [number]; }; } | { arr2: { [Op.contains]: [number]; }; })[]' is not assignable to type 'undefined'
So the question is what am I doing wrong, or in other words, how can I make that query without querying all records and filter using code
Thanks!

You have to use notIn and not contain maybe then it will work:
Official Docs: https://sequelize.org/master/manual/model-querying-basics.html
where: {
arr1: {
[Op.notIn]: someValueArray
},
arr2: {
[Op.notIn]: someValueArray
}
},

Apparently the second option is the correct one, but what was incorrect was the types of sequelize, #ts-ignore fixes the problem

Related

suitescript 2.0 unable to search inventorydetails subrecord from saved search data

I have created one saved search, and I am fetching data from by suitescript and here is the demo data response which I am getting this result from saved search response
{
"results": [
{
"recordType": "itemreceipt",
"id": "2572118",
"values": {
"trandate": "2021-3-25",
"type": [
{
"value": "ItemRcpt",
"text": "Item Receipt"
}
],
"tranid": "RCV123",
"salesrep": [
{
"value": "16018",
"text": "MXZ"
}
],
"entity": [
{
"value": "16993",
"text": "ABC"
}
],
"memo": "",
"amount": "1218.00",
"location": [
{
"value": "1",
"text": "XYZ"
}
],
"inventoryDetail.inventorynumber": [
{
"value": "10504",
"text": "3566044578"
}
]
}
}
]
}
AND I AM USING BELOW CODE TO MAKE FILTER BY inventoryDetail.inventorynumber FIELD WHICH IT MENTIONED IN SAVED SEARCH RESPONSE DATA AND IT THROWS ERROR "An nlobjSearchFilter contains invalid search criteria: inventoryDetail.issueinventorynumber."
but if I used tranid instead of inventoryDetail.issueinventorynumber then it does not throw the error, why I can not filter by inventoryDetail.inventorynumber I am trying since two days but no luck, please help me guys
/**
* #NApiVersion 2.1
* #NScriptType Restlet
* #NModuleScope Public
*/
/*
------------------------------------------------------------------------------------------
Script Information
------------------------------------------------------------------------------------------
Name:
Saved Search API
ID:
_saved_search_api
*/
var
log,
search,
response = new Object();
define( [ 'N/log', 'N/search' ], main );
function main( logModule, searchModule ) {
log = logModule;
search = searchModule;
return { post: postProcess }
}
function postProcess( request ) {
try {
var searchObj = search.load( { id: 1234 } );//saved search id
// Copy the filters from rs into defaultFilters.
var defaultFilters = searchObj.filters;
// below code works
defaultFilters.push(search.createFilter({
name: "tranid",
operator: search.Operator.IS,
values: ["RCV123"]
}));
// but this code does not works and it throws error "An nlobjSearchFilter contains invalid search criteria: inventoryDetail.issueinventorynumber."
/*defaultFilters.push(search.createFilter({
name: "inventoryDetail.inventorynumber",
operator: search.Operator.IS,
values: ["3566044578"]
}));*/
searchObj.filters = defaultFilters;
searchObj.filters = defaultFilters;
response.results = [];
var resultSet = searchObj.run();
var start = 0;
var results = [];
do {
results = resultSet.getRange( { start: start, end: start + 1000 } );
start += 1000;
response.results = response.results.concat( results ) ;
response.count =results.length;
} while ( results.length );
return response;
} catch( e ) {
log.debug( { 'title': 'error', 'details': e } );
return { 'error': { 'type': e.type, 'name': e.name, 'message': e.message } }
}
}
issueinventorynumber is not a valid search Column on the inventorydetail record. You are probably looking for inventorydetail.inventorynumber. You can reference the Search Columns section for the Inventory Detail within the Records Browser.
Be aware that Search Column names are not always the same as the field ID in the UI, as is the case here. The ID in the UI is issueinventorynumber, while the ID for the Search Column is inventorynumber.
Finally I found the solution
var transactionSearchObj = search.create({
type: "transaction",
filters:
[
["formulatext: {inventorydetail.inventorynumber}","contains","30124578547"]
],
columns:
[
search.createColumn({name: "trandate", label: "Date"}),
search.createColumn({name: "type", label: "Type"}),
search.createColumn({name: "tranid", label: "Document Number"}),
search.createColumn({name: "salesrep", label: "Sales Rep"}),
search.createColumn({name: "memo", label: "Memo"}),
search.createColumn({name: "amount", label: "Amount"}),
search.createColumn({name: "location", label: "Location"}),
search.createColumn({
name: "itemid",
join: "item",
label: "Name"
}),
search.createColumn({
name: "inventorynumber",
join: "inventoryDetail",
label: " Number"
})
]
});
return transactionSearchObj.run().getRange( { start: 0, end: 0 + 1000 } );

Loopback 4 auto generated model with required id failing validation

I'm using an automated script that runs an auto-generation model using lb4 cli.
Looks like validation expects id to be provided, but swagger missing it in its schema. Why I can't see the id property in swagger?
PLEASE NOTE! I don't want to modify manually my models
lb4 model activity --dataSource DS --table activity
Created model:
export class Activity extends Entity {
#property({
type: 'string',
required: true,
id: 1,
postgresql: {
columnName: 'id',
dataType: 'uuid',
dataLength: null,
dataPrecision: null,
dataScale: null,
nullable: 'NO',
},
})
id: string;
...
}
When I run the swagger tool and try to POST new activity, it missing the id field and returns the following error:
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "The `Activity` instance is not valid. Details: `id` can't be blank (value: undefined).",
"details": {
"context": "Activity",
"codes": {
"id": [
"presence"
]
},
"messages": {
"id": [
"can't be blank"
]
}
}
}
}
If I add a property id manually, then it throws a validation error:
{
"error": {
"statusCode": 422,
"name": "UnprocessableEntityError",
"message": "The request body is invalid. See error object `details` property for more info.",
"code": "VALIDATION_FAILED",
"details": [
{
"path": "",
"code": "additionalProperties",
"message": "must NOT have additional properties",
"info": {
"additionalProperty": "id"
}
}
]
}
}
Change your #model() by #model({settings: {strict: false}}) and add this line [prop: string]: any; into your model
#model({settings: {strict: false}})
[prop: string]: any;

Get JSON Array from JSON Object and Count Number of Objects

I have a column that contains some data like this:
{
"activity_goal": 200,
"members": [
{
"json": "data"
},
{
"HAHA": "HAHA"
},
{
"HAHA": "HAHA"
}
],
"name": "Hunters Team v3",
"total_activity": "0",
"revenue_goal": 200,
"total_active_days": "0",
"total_raised": 300
}
I am using cast(team_data -> 'members' as jsonb) to get the "Members" JSON array, which gives me a column like this:
[
{
"json": "data"
},
{
"HAHA": "HAHA"
},
{
"HAHA": "HAHA"
}
]
I am using array_length(cast(team_data -> 'members' as jsonb), 1) to pull a column with the number of Members that exist in the list. When I do this, I am given this error:
function array_length(jsonb, integer) does not exist
Note: I have also tried casting as "json" instead of "jsonb"
I am following this documentation. What am I doing wrong?
Use the JSON functions when working with json such as json_array_length
select json_array_length(team_data -> 'members') from mytable

How DataTables determine columns type

I have a dynamic table enhanced by jQuery DataTables, which display a custom object similar to this example.
JSON:
{
"data": [
{
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": {
"display": "SomeString",
"timestamp": 1303686000
},
"office": "Edinburgh",
"extn": "5421"
},
// ... skipped ...
]}
JavaScript:
$(document).ready(function() {
$('#example').DataTable( {
ajax: "data/orthogonal.txt",
columns: [
{ data: "name" },
{ data: "position" },
{ data: "office" },
{ data: "extn" },
{ data: {
_: "start_date.display",
sort: "start_date.timestamp"
} },
{ data: "salary" }
]
} );
} );
The difference is that I dynamically build the columns configuration, because the columns can be in any order, and others columns can be added or removed from the list. For this example (my case is very similar) the problem is that for some reason the timestamp property is ordered as a String instead of being ordered as a number.
I discovered that after setting the column "type" as "number" the ordering works perfectly. I'm presuming that DataTables is auto detecting the column as "String" for some reason (maybe because the display element is a string).
How does DataTables set the type of the columns, when is not explicitly declared?
Edit 1
I made a sample code to show the problem
http://jsfiddle.net/Teles/agrLjd2n/16/
jQuery DataTables has built-in mechanism for type detection. There are multiple predefined functions for various types with fallback to string data type.
It's also possible to use third-party plug-ins or write your own.
There are multiple ways to specify data type, below are just the few.
SOLUTION 1
Use type option.
$(document).ready(function() {
$('#example').DataTable( {
ajax: "data/orthogonal.txt",
columns: [
{ data: "name" },
{ data: "position" },
{ data: "office" },
{ data: "extn" },
{ data: "start_date.display", type: "date" },
{ data: "salary" }
]
} );
} );
SOLUTION 2
Use returned JSON data for type detection, see columns.data for more information.
$(document).ready(function() {
$('#example').DataTable( {
ajax: "data/orthogonal.txt",
columns: [
{ data: "name" },
{ data: "position" },
{ data: "office" },
{ data: "extn" },
{ data: {
_: "start_date.display",
sort: "start_date.timestamp",
type: "start_date.timestamp",
} },
{ data: "salary" }
]
} );
} );
DataTables always check the "type" property of the column "data" to auto detect the type of the column, if no "type" property is specified it will check the default value "_".
So if you want DataTables to auto detect the type of the column checking the type of your "sort" property you should set the "type" property of data to be equals to your "sort" value
Here is a sample code with different approchs to achieve what I was tryng to do. Thanks #Gyrocode.com and #davidkonrad.
var Cell = function(display, value) {
this.display = display;
this.value = value;
}
$(document).ready(function() {
var cells = [
new Cell("120 (10%)", 120),
new Cell("60 (5%)", 60),
new Cell("30 (2.5%)", 30)
];
$('#example').DataTable( {
data: cells,
columns: [
{
title : "Column NOT OK",
data: {
_: "display",
sort: "value"
}
}, {
type : "num",
title : "Column Ok setting column type",
data: {
_: "display",
sort: "value"
}
}, {
title : "Column Ok changing default value",
data: {
_: "value",
display: "display",
filter: "display"
}
}, {
title : "Column Ok setting data type",
data: {
_: "display",
sort: "value",
type: "value"
}
}, {
type : "num",
title : "Column Not OK",
data: "display"
}
]
} );
} );

How to query mongodb with “like” for number data type? [duplicate]

I want to regex search an integer value in MongoDB. Is this possible?
I'm building a CRUD type interface that allows * for wildcards on the various fields. I'm trying to keep the UI consistent for a few fields that are integers.
Consider:
> db.seDemo.insert({ "example" : 1234 });
> db.seDemo.find({ "example" : 1234 });
{ "_id" : ObjectId("4bfc2bfea2004adae015220a"), "example" : 1234 }
> db.seDemo.find({ "example" : /^123.*/ });
>
As you can see, I insert an object and I'm able to find it by the value. If I try a simple regex, I can't actually find the object.
Thanks!
If you are wanting to do a pattern match on numbers, the way to do it in mongo is use the $where expression and pass in a pattern match.
> db.test.find({ $where: "/^123.*/.test(this.example)" })
{ "_id" : ObjectId("4bfc3187fec861325f34b132"), "example" : 1234 }
I am not a big fan of using the $where query operator because of the way it evaluates the query expression, it doesn't use indexes and the security risk if the query uses user input data.
Starting from MongoDB 4.2 you can use the $regexMatch|$regexFind|$regexFindAll available in MongoDB 4.1.9+ and the $expr to do this.
let regex = /123/;
$regexMatch and $regexFind
db.col.find({
"$expr": {
"$regexMatch": {
"input": {"$toString": "$name"},
"regex": /123/
}
}
})
$regexFinAll
db.col.find({
"$expr": {
"$gt": [
{
"$size": {
"$regexFindAll": {
"input": {"$toString": "$name"},
"regex": "123"
}
}
},
0
]
}
})
From MongoDB 4.0 you can use the $toString operator which is a wrapper around the $convert operator to stringify integers.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toString": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])
If what you want is retrieve all the document which contain a particular substring, starting from release 3.4, you can use the $redact operator which allows a $conditional logic processing.$indexOfCP.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toLower": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])
which produces:
{
"_id" : ObjectId("579c668c1c52188b56a235b7"),
"example" : 1234
}
{
"_id" : ObjectId("579c66971c52188b56a235b9"),
"example" : 12334
}
Prior to MongoDB 3.4, you need to $project your document and add another computed field which is the string value of your number.
The $toLower and his sibling $toUpper operators respectively convert a string to lowercase and uppercase but they have a little unknown feature which is that they can be used to convert an integer to string.
The $match operator returns all those documents that match your pattern using the $regex operator.
db.seDemo.aggregate(
[
{ "$project": {
"stringifyExample": { "$toLower": "$example" },
"example": 1
}},
{ "$match": { "stringifyExample": /^123.*/ } }
]
)
which yields:
{
"_id" : ObjectId("579c668c1c52188b56a235b7"),
"example" : 1234,
"stringifyExample" : "1234"
}
{
"_id" : ObjectId("579c66971c52188b56a235b9"),
"example" : 12334,
"stringifyExample" : "12334"
}
Now, if what you want is retrieve all the document which contain a particular substring, the easier and better way to do this is in the upcoming release of MongoDB (as of this writing) using the $redact operator which allows a $conditional logic processing.$indexOfCP.
db.seDemo.aggregate([
{ "$redact": {
"$cond": [
{ "$gt": [
{ "$indexOfCP": [
{ "$toLower": "$example" },
"123"
] },
-1
] },
"$$KEEP",
"$$PRUNE"
]
}}
])