SQL update in JSON - sql

I'm having trouble updating a JSON object, which is represented as an object rather than an array. I need to dynamically bypass all the keys, but they have a random number in their name, which can be absolutely anything (there is no way to change the JSON view) and get to the visibility to change its value. For example:
Set the visibility to false for all bicycle keys
{
"objects": {
"object1": {
"components": {
"car": { "visibility": true},
"bicycle": { "visibility": true},
"bicycle1": { "visibility": true},
"bicycle2": { "visibility": true},
"van": { "visibility": true}
}
},
"object2": {
"components": {
"car": { "visibility": true},
"bicycle5": { "visibility": true},
"van": { "visibility": true}
}
}
},
"objectN": {
"components": {
"car": { "visibility": true},
"bicycle": { "visibility": true},
"bicycle3": { "visibility": true},
"van": { "visibility": true}
}
}
}
}
Result JSON
{
"objects": {
"object1": {
"components": {
"car": { "visibility": true},
"bicycle": { "visibility": false},
"bicycle1": { "visibility": false},
"bicycle2": { "visibility": false},
"van": { "visibility": true}
}
},
"object2": {
"components": {
"bicycle5": { "visibility": false},
"van": { "visibility": true}
}
}
},
"objectN": {
"components": {
"car": { "visibility": true},
"bicycle": { "visibility": false},
"bicycle3": { "visibility": false},
"van": { "visibility": true}
}
}
}
}
I have attempted to use JSON_MODIFY and OPEN_JSON, but as I am new to SQL, I am having trouble. I would appreciate any help or suggestions.

Related

How to group by in MongoDB Compass based on the time?

Recently I'm working with a Mongodb database. Here is the data model of the document I need to run a query on:
{
"creation_date": {
"$date": {
"$numberLong": "1641981205813"
}
},
"user_id": {
"$oid": "61dedd8b7a520461dd78016b"
},
"products": [
{
"_id": {
"$oid": "61dede397a520461dd7818bd"
},
"product_id": {
"$oid": "615071ae8b66e1e9a3d6ea50"
},
"payment": true,
"support_all_payment": false,
"term_ids": null
}
],
"carts_info": [
{
"_id": {
"$oid": "61dede397a520461dd7818be"
},
"support_type": null,
"support_price": 0,
"product_price": 11000,
"product_type": "all",
"final_price": 11000,
"product_id": {
"$oid": "615071ae8b66e1e9a3d6ea50"
}
}
],
"_des": "initial_payment",
"_type": "online",
"_token": "9e0cb4d111f642f1a6f482bb04f1f57b",
"_price": 11000,
"_status": "unpaid",
"_terminal_id": "12605682",
"__v": 0,
"additional_information": {
"saman_bank": {
"MID": "0",
"ResNum": "61dede387a520461dd7818bb",
"State": "CanceledByUser",
"TraceNo": "",
"Wage": "",
"Rrn": "",
"SecurePan": "",
"HashedCardNumber": "",
"Status": "1"
}
}
}
This collection is user orders. I need to count the orders for today. So, I need such a equivalent query for Mongodb Compass the same as this SQL:
SELECT count(1) num,
date(creation_date) date
FROM orders
WHERE date(creation_date) = "2023-02-16"
GROUP BY date
Any idea how can I run this logic on Mongodb Compass?
Use $dateTrunc to perform date only operations.
db.collection.aggregate([
{
"$match": {
$expr: {
$eq: [
{
$dateTrunc: {
date: "$creation_date",
unit: "day"
}
},
ISODate("2022-01-12")
]
}
}
},
{
$group: {
_id: {
$dateTrunc: {
date: "$creation_date",
unit: "day"
}
},
num: {
$sum: 1
}
}
}
])
Mongo Playground
For OP's MongoDB v3.6, we can use $dateToString to perform string comparison on a date-only string.
db.collection.aggregate([
{
$addFields: {
dateOnly: {
"$dateToString": {
"date": "$creation_date",
"format": "%Y-%m-%d"
}
}
}
},
{
$match: {
dateOnly: "2022-01-12"
}
},
{
$group: {
_id: null,
num: {
$sum: 1
}
}
}
])
Mongo Playground

MongoDB Lookup values based on dynamic field name

I'm pretty sure the below can be done, I'm struggling to understand how to do it in MongoDB.
My data is structured like this (demo data):
db={
"recipes": [
{
"id": 1,
"name": "flatbread pizza",
"ingredients": {
"1010": 1,
"1020": 2,
"1030": 200
}
},
{
"id": 2,
"name": "cheese sandwich",
"ingredients": {
"1040": 1,
"1050": 2
}
}
],
"ingredients": [
{
"id": 1010,
"name": "flatbread",
"unit": "pieces"
},
{
"id": 1020,
"name": "garlic",
"unit": "clove"
},
{
"id": 1030,
"name": "tomato sauce",
"unit": "ml"
},
{
"id": 1040,
"name": "bread",
"unit": "slices"
},
{
"id": 1050,
"name": "cheese",
"unit": "slices"
}
]
}
The output I'm trying to achieve would look like this:
[
{
"id": 1,
"name": "flatbread pizza",
“flatbread”: “1 pieces”,
“garlic”: “2 cloves”,
“tomato sauce”: “200 ml”
},
{
"id": 2,
"name": "cheese sandwich",
“bread”: “1 slices”,
“cheese”: “2 slices”
}
]
I've tried several approaches, and I get stuck at the bit where I need to do a lookup based on the ingredient name (which actually is the id). I tried using $objectToArray to turn it into a k-v document, but then I get stuck in how to construct the lookup pipeline.
This is not a simple solution, and probably can be improved:
db.recipes.aggregate([
{
"$addFields": {
ingredientsParts: {
"$objectToArray": "$ingredients"
}
}
},
{
$unwind: "$ingredientsParts"
},
{
"$group": {
_id: "$id",
name: {
$first: "$name"
},
ingredientsParts: {
$push: {
v: "$ingredientsParts.v",
id: {
$toInt: "$ingredientsParts.k"
}
}
}
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "ingredientsParts.id",
"foreignField": "id",
"as": "ingredients"
}
},
{
$unwind: "$ingredients"
},
{
"$addFields": {
"ingredientsPart": {
"$filter": {
input: "$ingredientsParts",
as: "item",
cond: {
$eq: [
"$$item.id",
"$ingredients.id"
]
}
}
}
}
},
{
$project: {
ingredients: 1,
ingredientsPart: {
"$arrayElemAt": [
"$ingredientsPart",
0
]
},
name: 1
}
},
{
"$addFields": {
units: {
k: "$ingredients.name",
v: {
"$concat": [
{
$toString: "$ingredientsPart.v"
},
" ",
"$ingredients.unit"
]
}
}
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
units: {
$push: "$units"
}
}
},
{
"$addFields": {
"data": {
"$arrayToObject": "$units"
}
}
},
{
"$addFields": {
"data.id": "$_id",
"data.name": "$name"
}
},
{
"$replaceRoot": {
"newRoot": "$data"
}
}
])
You can see it works here
As rickhg12hs said, it can be modeled better.

mongodb filter array of nested documents

I want to find one and filter profile like that by moduleId and name
{
"moduleId": 1,
"access": {
"del": ..,
"editWrite": ...,
"read": ....
}
}
the document looks like this:
"profileAccess": [
{
"moduleId": 1,
"access": {
"del": true,
"editWrite": true,
"read": true
}
},
{
"moduleId": 2,
"access": {
"del": true,
"editWrite": true,
"read": true
}
}
],
"name": "admin"
},
found the answer it seems i forget to return the response
Profile.findOne({name:"admin"},{profileAccess: { $elemMatch: { moduleId: 1} }});

Swagger Schema: oneOf, anyOf, allOf valid at the same time?

I'm just reading through the more advanced validators in the Schema definition of the Swagger specification:
{
"Schema":{
"type":"object",
"properties":{
"title":{
"type":"string"
},
"multipleOf":{
"type":"number",
"minimum":0,
"exclusiveMinimum":true
},
"maximum":{
"type":"number"
},
"exclusiveMaximum":{
"type":"boolean",
"default":false
},
"minimum":{
"type":"number"
},
"exclusiveMinimum":{
"type":"boolean",
"default":false
},
"maxLength":{
"type":"integer",
"minimum":0
},
"minLength":{
"type":"integer",
"minimum":0,
"default":0
},
"pattern":{
"type":"string",
"format":"regex"
},
"maxItems":{
"type":"integer",
"minimum":0
},
"minItems":{
"type":"integer",
"minimum":0,
"default":0
},
"uniqueItems":{
"type":"boolean",
"default":false
},
"maxProperties":{
"type":"integer",
"minimum":0
},
"minProperties":{
"type":"integer",
"minimum":0,
"default":0
},
"required":{
"type":"array",
"items":{
"type":"string"
},
"minItems":1,
"uniqueItems":true
},
"enum":{
"type":"array",
"items":{
},
"minItems":1,
"uniqueItems":true
},
"type":{
"type":"string",
"enum":[
"array",
"boolean",
"integer",
"number",
"object",
"string"
]
},
"not":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
},
"allOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"oneOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"anyOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
},
"properties":{
"type":"object",
"additionalProperties":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"additionalProperties":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
},
{
"type":"boolean"
}
],
"default":true
},
"description":{
"type":"string"
},
"format":{
"type":"string"
},
"default":{
},
"nullable":{
"type":"boolean",
"default":false
},
"discriminator":{
"$ref":"#/definitions/Discriminator"
},
"readOnly":{
"type":"boolean",
"default":false
},
"writeOnly":{
"type":"boolean",
"default":false
},
"example":{
},
"externalDocs":{
"$ref":"#/definitions/ExternalDocumentation"
},
"deprecated":{
"type":"boolean",
"default":false
},
"xml":{
"$ref":"#/definitions/XML"
}
},
"patternProperties":{
"^x-":{
}
},
"additionalProperties":false
}
}
The thing that I am thinking about is combinations of the anyOf, allOf, oneOf and not keywords. I have two questions.
The first question is: "can they be used in conjunction"? Like so:
{
"allOf" : [
{
"minItems" : 0
},
{
"maxItems" : 10
}
],
"anyOf" : [
{
"type" : "array",
"items" : {
"type" : "string"
}
},
{
"type" : "array",
"items" : {
"type" : "integer"
}
}
]
}
This example is, of course, needlessly complicated. But is it valid? Or can you only use one modifier but not the others?
The second question is, can anybody point me to a real-world example where one of these operators have been used in conjunction?
The thing that I am thinking about is combinations of the anyOf, allOf, oneOf and not keywords. I have two questions.
The first question is: "can they be used in conjunction"?
Yes, allOf, anyOf, oneOf and not can be used in conjunction. OpenAPI Specification follows the rules of JSON Schema here, and in JSON Schema adjacent keywords work as branches of an implicit allOf (source). So your example is equivalent to:
{
"allOf": [
{
"allOf": [
{
"minItems": 0
},
{
"maxItems": 10
}
]
},
{
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "array",
"items": {
"type": "integer"
}
}
]
}
]
}
That said, this example is too complex and can be simplified into:
{
"minItems": 0,
"maxItems": 10,
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
}
}

Cannot get Buttons csv working in DataTables 1.10.11

I am upgrading an existing site that was using DataTables 1.9.4 and TableTools 2.0.3 to use DataTables 1.10.11. I cannot get the csv button to show up on my page.
I replaced
"oTableTools": {
"sSwfPath": "scripts/jquery/TableTools-2.0.3/media/swf/copy_csv_xls.swf",
"sRowSelect": "multi",
"aButtons": [
{
"sExtends": "text",
"sButtonText": t.cmdMarkSelectedInvoiced,
"fnClick": function (nButton, oConfig, oFlash) {
vr.markSelectedInvoiced();
}
},
{
"sExtends": "csv",
"sButtonText": t.cmdExportSelectedToCSV,
"bSelectedOnly": true
},
{
"sExtends": "csv",
"sButtonText": t.cmdExportAllToCSV
},
{
"sExtends": "select_none",
"sButtonText": t.cmdDeselectAll
}
]
},
with
"buttons": ['csv'],
the new initialization for the datatable is:
var bla = $('#someelement').DataTable({
"buttons": [
'csv'
],
"pagingType": "simple",
"destroy": true,
"stateSave": true,
"stateSaveCallback": function (settings, data) {
vr.saveDtState(data);
},
"stateLoadCallback": function (settings) {
return vr.dtSavedState(settings);
},
"pageLength": 10,
"language": {
"emptyTable": t.tblInfoNoDesignRequestFound,
"infoEmpty": t.tblInfoNoDesignRequestFound,
"zeroRecords": t.tblInfoNoDesignRequestFound,
"info": ct.tblInfoTxtDisplayingXtoYofTotal,
"infoFiltered": ct.tblInfoTxtFilteredFromMax,
"lengthMenu": ct.tblInfoTxtShow + ' <select>' + '<option selected value=10>10</option>' + '<option value=15>15</option>' + '<option value=20>20</option>' + '<option value=25>25</option>' + '<option value=-1>' + ct.txtAll + '</option>' + '</select> ' + ct.tblInfoTxtRows,
"search": ct.tblInfoTxtFilter,
"paginate": {
"next": ct.tblInfoTxtNextPage,
"previous": ct.tblInfoTxtPreviousPage
}
},
"ordering": true,
"order": [],
"stripeClasses": [
'myodd',
'myeven'
],
"data": vr.dataObj.data,
"columns": [
{
"data": "companyLocation",
"title": ct.chCompanyLocation
},
{
"data": function (source, type, val) {
if (type === 'display' || type === 'filter') {
return u.jsonToLocalDate(source.requestStatusDateUtc, false);
}
return source.requestStatusDateUtc;
},
"title": ct.chDate
},
{
"data": function (source, type, val) {
return vr.formattedNameSizeAndOrient(source, type)
},
"title": ct.chLogoName
},
{
"data": function (source, type, val) {
return vr.formattedDrInfo(source, type)
},
"title": ct.chDRNumber
},
{
"data": "requestStatusDescription",
"title": ct.chStatus
},
{
"data": "invoiceAmount",
"title": ct.chInvoiceAmount,
"orderable": false,
"className": "rightJustify"
},
{
"data": "invoiceCurrency",
"bSortable": false
},
{
"data": "requestedBy",
"title": ct.chCreatedByName,
"orderable": false
}
],
"initComplete": function () {
vr.loadColumnSelects('viewRequestsDataTable', this, columnSelects);
}
});
You need to specify the dom: parameter.