MongoDB convert Select from UNION with Group By with sum - mysql

I'm building a COVID API in NodeJS which have very in-depth detail about my country.
Due huge bill I decided to rewrite my whole database from MySQL to NoSQL which is more affordable for me.
Basically what I have to do is, if date_onset is empty then I will use date_specimen as proxy.
I have the following MySQL query which I need to convert to NoSQL.
SELECT count(a.cases) as cases, a.date FROM
(SELECT date_specimen AS cases, date_specimen AS date from case_informations WHERE (date_specimen <> '' AND date_onset = '')
UNION ALL
SELECT date_onset AS cases, date_onset AS date FROM case_informations WHERE date_onset <> '') AS a
GROUP BY a.date ORDER BY a.date ASC
The Document:
{
"_id": {
"$oid": "5f29a6dcc4ce73be6be928ff"
},
"case_code": "C611583",
"age": 20,
"age_group": "20-24",
"sex": "female",
"date_specimen": "",
"date_result_release": "2020-04-22",
"date_rep_conf": "2020-04-24",
"date_died": "",
"date_recover": "",
"removal_type": "recovered",
"admitted": "no",
"region_res": "NCR",
"prov_res": "",
"city_mun_res": "",
"city_muni_psgc": "",
"health_status": "recovered",
"quarantined": "no",
"date_onset": "",
"pregnant_tab": "no",
"validation_status": "Removal Type is \"Recovered\", but no Recovered Date is recorded\nRemoval Type is \"Recovered\", but no Recovered Date is recorded\nHealth Status is \"Recovered\", but no Date Recovered is recorded\nHealth Status is \"Recovered\", but no Date Recovered is recorded"
}
This is the closest I can get:
collection.aggregate([
{$project: {date_specimen: 1, date_onset: 1}},
{$lookup:
{
from: 'case_informations',
pipeline: [
{$match: {date_specimen: {$exists: true}, date_onset: ''}},
{$group: {_id: '$date_specimen', cases: {$sum: 1}}},
{$sort: {_id: 1}},
],
as: 'a',
},
},
{$lookup:
{
from: 'case_informations',
pipeline: [
{$match: {date_onset: {$exists: true}}},
{$group: {_id: '$date_onset', cases: {$sum: 1}}},
{$sort: {_id: 1}},
],
as: 'b',
},
},
{$project: {'a': 1, 'b': 1}},
]).limit(1);
result:
{
_id: 5f29a6dcc4ce73be6be928fc,
a: [
{ _id: '2020-03-04', cases: 1 },
{ _id: '2020-03-06', cases: 8 },
{ _id: '2020-03-07', cases: 48 },
{...}
],
b: [
{ _id: '2020-03-03', cases: 45 },
{ _id: '2020-03-04', cases: 32 },
{ _id: '2020-03-05', cases: 55 },
{...}
]
}
expected:
{
_id: 5f29a6dcc4ce73be6be928fc,
UnionOfAandC: [
{ _id: '2020-03-03', cases: 45 },
{ _id: '2020-03-04', cases: 33 }, // merge object with same date
{ _id: '2020-03-05', cases: 55 },
{ _id: '2020-03-06', cases: 8 },
{ _id: '2020-03-07', cases: 48 },
{...},
],
}

After some trial and error I finally solved it
await collection.aggregate([
{$match: {$or: [{'date_onset': {'$ne': ''}}, {'date_specimen': {'$ne': ''}}]}},
{
$group: {
_id: {
'date': {
$cond: {
if: {$eq: ['$date_onset', '']}, then: '$date_specimen', else: '$date_onset',
},
},
},
cases: {$sum: 1},
},
},
{$sort: {'_id.date': 1}},
{$project: {'_id': 0, 'date': '$_id.date', 'cases': 1}},
]);

Related

how to query mongodb nested query three level?

I have three collections (docs example struct see below :)
my mongodb version is 4.4
section
{
_id: ObjectId('62b131211331e0e9ba284187'),
name: 'name1',
},
{
_id: ObjectId('62b131211331e0e9ba284187'),
name: 'name2',
}
...
2.problems
{
_id: ObjectId('62b13d5f1331e0e9ba2841e6'),
title: 'title1',
score: 10,
section_id: ObjectId('62b131211331e0e9ba284188')
},
{
_id: ObjectId('62b13d5f1331e0e9ba2841e6'),
title: 'title2',
score: 20,
section_id: ObjectId('62b131211331e0e9ba284188')
},
{
_id: ObjectId('62b13d5f1331e0e9ba2841e6'),
title: 'title3',
score: 30,
section_id: ObjectId('62b131211331e0e9ba284188')
}
...
3.choices
{
_id: ObjectId('62b164ae1331e0e9ba284236'),
text: 'text1',
value: 0,
checked: false,
problem_id: ObjectId('62b13d5f1331e0e9ba2841ed')
},
{
_id: ObjectId('62b164ae1331e0e9ba284236'),
text: 'text2',
value: 0,
checked: false,
problem_id: ObjectId('62b13d5f1331e0e9ba2841ed')
},
{
_id: ObjectId('62b164ae1331e0e9ba284236'),
text: 'text3',
value: 0,
checked: false,
problem_id: ObjectId('62b13d5f1331e0e9ba2841ed')
},
...
the relationship of those collections
sections has many problems
problems has many choices
My question is :
Now I have an array of sections's id like below:
[
ObjectId('62b131211331e0e9ba284188'),
ObjectId('62b131211331e0e9ba28418a'),
ObjectId('62b131211331e0e9ba28418c')
]
I want to perform one query get the result like below:
[
{
_id: ObjectId('62b131211331e0e9ba284187'),
name: 'name1',
problems: [
{
_id: ObjectId('62b13d5f1331e0e9ba2841e6'),
title: 'title1',
score: 10,
section_id: ObjectId('62b131211331e0e9ba284188'),
choices: [
{}, // choice doc
]
},
{
_id: ObjectId('62b13d5f1331e0e9ba2841e6'),
title: 'title2',
score: 10,
section_id: ObjectId('62b131211331e0e9ba284188'),
choices: [
{}, // choice doc
]
},
...
]
},
{
_id: ObjectId('62b131211331e0e9ba284187'),
name: 'name1',
problems: [
{},
]
},
{
_id: ObjectId('62b131211331e0e9ba284187'),
name: 'name1',
problems: [
{},
]
}
]
I have try run this query in my mongoexpress but it didn't work:
// match stage (ps: start with sections collection)
{
"_id": {
$in: [
ObjectId('62b131211331e0e9ba284188'),
ObjectId('62b131211331e0e9ba28418a'),
ObjectId('62b131211331e0e9ba28418c')
]
}
// lookup stage
{
from: 'problems',
let: {"sid": "$_id"},
pipeline: [
{
"$match": {
"$expr": {
"$eq": ["$section_id", "$$sid"]
},
},
},
{
"$lookup": {
from: "choices",
let: {"chid": "$_id"},
pipeline: [
{
"$match": {
"$expr": {},
},
},
],
as: "choices"
},
},
],
as: "problems"
}

Sequelize find sum in Many to Many Relationship

I need to build a many-to-many relationship between entities Product and Store(Wharehouse).
So I managed to build a relationship with Sequlize like this.
Product.belongsToMany(Store, { through: 'product_store' });
Store.belongsToMany(Product, { through: 'product_store' });
product_store is the table that holds the relationship with Store and Product. When saving a product in a store in need some additional details like quantity so I added a field to the product_store
const Product_Store = sequelize.define("product_store", {
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
},
uid: {
type: STRING,
allowNull: false,
unique: true,
},
ws_price: {
type: DECIMAL(10, 2),
},
discount: {
type: DECIMAL(10, 2),
},
bonus: {
type: DECIMAL(10, 2),
},
quantity: {
type: DECIMAL(10, 2),
},
total: {
type: DECIMAL(10, 2),
},
active: {
type: BOOLEAN,
defaultValue: true,
},
createdAt: {
type: DATE,
},
updatedAt: { type: DATE },
});
I managed to save the product in the store in the following way
await store.addProduct(product, {
through: {
uid: "3462",
ws_price: 100,
discount: 2,
bonus: 1,
quantity: 2000,
total: 200000,
}
})
The values are saved properly and I could get products with store.getProdcuts(). But now I need to query the products and the sum of their quantities in all stores. I've started to query it with
let products = await Product.findAll({
include: {
model: Store,
through: { attributes: ["ws_price", "discount", "bonus", "quantity", "total"] }
}
})
Which queries the product with store details(including the quantity) like this
[
{
"id": 1,
"uid": "4323",
"name": "Sunlight",
"active": true,
"createdAt": "2022-01-24T06:38:47.000Z",
"updatedAt": "2022-01-24T06:38:47.000Z",
"supplierId": null,
"typeId": null,
"unitId": null,
"stores": [
{
"id": 1,
"uid": "122333",
"name": "Store1",
"active": true,
"createdAt": "2022-01-24T06:38:47.000Z",
"updatedAt": "2022-01-24T06:38:47.000Z",
"product_store": {
"ws_price": "150.00",
"discount": "2.00",
"bonus": "1.00",
"quantity": "2000.00",
"total": "300000.00"
}
},
{
"id": 2,
"uid": "34523",
"name": "Store2",
"active": true,
"createdAt": "2022-01-24T06:38:47.000Z",
"updatedAt": "2022-01-24T06:38:47.000Z",
"product_store": {
"ws_price": "300.00",
"discount": "2.00",
"bonus": "1.00",
"quantity": "3000.00",
"total": "300000.00"
}
}
]
}
]
I only need to get the product details and the sum of product in all stores how can I achieve this?. I'm not familiar with using Count/Sum with relationships. Thanks in advance!
The most correct way is to use a subquery via Sequelize.literal like this:
let products = await Product.findAll({
attributes: {
include: [
[Sequelize.literal('(SELECT sum(product_store.quantity) FROM product_store WHERE product_store.product_id=product.id)'), 'product_quantity']
]
}
})

{this.state.object} Objects are not valid as a React child

I have a response json like this:
{
"variables": {
"lock": 0,
"pos": 55,
"pos_on": 55,
"pos_off": 150
},
"id": "11",
"name": "Lock_table_2",
"hardware": "esp8266",
"connected": true
}
and I try to show the lock value in 'variables' object
so I write
constructor(props) {
super(props)
this.state = {
dock_1: {}, // define a empty json
dock_2: {},
dock_3: {},
}
}
pingIP() {
axios
.get('http://192.168.50.225:8888/test_check')
.then(response => {
let data = response.data.list; // return value is a list
this.setState({ // every 2 sec setState
dock_1: data[0], // data[0] -> 192.168.50.40's json
dock_2: data[1],
dock_3: data[2],
})
})
}
render(){
return (
<p>{this.state.dock_1.variables.lock}</p>
);
}
but I got this error
in here
So I tried this
render(){
return (
<p>{this.state.dock_1.variables}</p>
);
}
then here comes the another error message
in here
here is the get request return value
{
"list": [
{
"connected": true,
"hardware": "esp8266",
"id": "10",
"name": "Lock_table_1",
"variables": {
"lock": 1,
"pos": 80,
"pos_off": 160,
"pos_on": 80
}
},
{
"connected": true,
"hardware": "esp8266",
"id": "10",
"name": "Lock_table_2",
"variables": {
"lock": 1,
"pos": 80,
"pos_off": 160,
"pos_on": 80
}
},
{
"connected": true,
"hardware": "esp8266",
"id": "10",
"name": "Lock_table_3",
"variables": {
"lock": 1,
"pos": 80,
"pos_off": 160,
"pos_on": 80
}
}
]
}
the return value is a list
in order to get first value so I wrote data[0], data1 ...
what's happening in here?
I think your response is an array of 3 items like this:
[
{
variables: {
lock: 0,
pos: 55,
pos_on: 55,
pos_off: 150
},
id: "11",
name: "Lock_table_2",
hardware: "esp8266",
connected: true
},
{
variables: {
lock: 1,
pos: 44,
pos_on: 56,
pos_off: 151
},
id: "11",
name: "Lock_table_3",
hardware: "esp8267",
connected: false
},
{
variables: {
lock: 2,
pos: 45,
pos_on: 57,
pos_off: 152
},
id: "11",
name: "Lock_table_4",
hardware: "esp8268",
connected: true
}
]
So you can access the dock 1 variable lock using Inline If with Logical && Operator to prevent null exception.
<p>{this.state.dock_1.variables && this.state.dock_1.variables.lock}</p>
A sample working codesandbox with a fake api:
https://codesandbox.io/s/stoic-chaplygin-r1yxd

How to write Query to retrieve every subdocument array who matches

Here i need my explain my problem clearly. How can i write a query to retrieve every subdocument array who matches the condition using mongoose and nodejs.
this is my existing JSON:
[
{
_id: "568ccd6e646489f4106470ec",
area_name: "Padi",
warehouse_name: "Hapserve Online Water Service",
name: "Ganesh",
email: "ganesh#excrin.com",
mobile_no: "9042391491",
otp: "4466",
__v: 0,
date: "06-01-2016",
booking:
[
{
can_quantity: "4",
delivery_date: "06-01-2016",
delivery_timeslot: "10am-3pm",
subscription: "true",
subscription_type: "Weekly",
total_cost: "240",
order_id: "S13833",
can_name: "Tata Waters",
address: "15/A,Ramanrajan street,,Padi,Chennai",
can_cost: "240",
_id: "568ccd6e646489f4106470ee",
ordered_at: "2016-01-06T08:16:46.825Z",
status: "UnderProcess"
},
{
can_name: "Bisleri",
can_quantity: "4",
can_cost: "200",
delivery_date: "11-01-2016",
delivery_timeslot: "3pm-8pm",
order_id: "11537",
address: "27,Main Street,Padi,Chennai",
_id: "5693860edb988e241102d196",
ordered_at: "2016-01-11T10:38:06.749Z",
status: "UnderProcess"
}
]
},
{
_id: "56937fb8920629a0164604d8",
area_name: "Poonamallee",
warehouse_name: "Tata Waters",
name: "M.Kalaiselvan",
email: "kalai131192#gmail.com",
mobile_no: "9003321521",
otp: "2256",
__v: 0,
date: "2016-01-11T10:11:04.266Z",
booking:
[
{
can_quantity: "4",
delivery_date: "06-01-2016",
delivery_timeslot: "10am-3pm",
subscription: "true",
subscription_type: "Alternate",
total_cost: "640",
order_id: "S13406",
can_name: "Kinley",
address: "133,Bajanai koil street, Melmanagar,Poonamallee,Chennai",
can_cost: "160",
_id: "56937fb8920629a0164604da",
ordered_at: "11-01-2016",
status: "UnderProcess"
},
{
can_name: "Tata Waters",
can_quantity: "2",
can_cost: "120",
delivery_date: "11-01-2016",
delivery_timeslot: "10am-3pm",
order_id: "11387",
address: "140,Bajanai koil street, Melmanagar,Poonamallee,Chennai",
_id: "56937ff7920629a0164604dc",
ordered_at: "2016-01-11T10:12:07.719Z",
status: "UnderProcess"
},
{
can_name: "Bisleri",
can_quantity: "4",
can_cost: "200",
delivery_date: "12-01-2016",
delivery_timeslot: "10am-3pm",
order_id: "16853",
address: "140,Bajanai koil street, Melmanagar,Poonamallee,Chennai",
_id: "56938584db988e241102d194",
ordered_at: "2016-01-11T10:35:48.911Z",
status: "UnderProcess"
},
{
can_name: "Hapserve",
can_quantity: "6",
can_cost: "150",
delivery_date: "11-01-2016",
delivery_timeslot: "10am-3pm",
order_id: "17397",
address: "133,Bajanai koil street, Melmanagar,Poonamallee,Chennai",
_id: "569385bbdb988e241102d195",
ordered_at: "2016-01-11T10:36:43.918Z",
status: "UnderProcess"
},
{
can_name: "Bisleri",
can_quantity: "5",
can_cost: "250",
delivery_date: "11-01-2016",
delivery_timeslot: "10am-3pm",
order_id: "14218",
address: "133,Bajanai koil street, Melmanagar,Poonamallee,Chennai",
_id: "56939a13c898ef7c0cc882b0",
ordered_at: "2016-01-11T12:03:31.324Z",
status: "Cancelled"
}
]
}
]
Here i need to retrieve every document where delivery date is today
so this is my nodejs route
router.get('/booking-date/:date', function(req, res){
var id = req.params.date;
RegisterList.find({'booking.delivery_date':id}, {'booking.$':1}, function(err, docs){
if(err)
throw err;
res.json(docs);
});
});
while am using this am not able to get every data. only two data is retrieve from collection.
example if i search for a date 11-01-2016 am getting only one subdocument for
each parent id, but in the above json for date 11-01-2016. for one parent id has 2 subdocument for that date and another parent id has 1 subdocument for that date.
am not able to write mongoose query retrieve to every subdocument where matches done..
Help will be appreciated...
Sounds like you may want to try the aggregation framework where you can $project the booking array with a filter made possible using the $setDifference, $map and $cond operators.
The $map operator inspects each element within the booking array and the $cond operator returns only the wanted fields based on a true condtion, a false value is returned on the contrary instead of the array element. $setDifference operator then removes all false values from the array by comparing to another set with the [false] values, the final result is only the returned matches:
router.get('/booking-date/:date', function(req, res){
var id = req.params.date,
pipeline = [
{
"$match": { 'booking.delivery_date': id }
},
{
"$project": {
"booking": {
"$setDifference": [
{
"$map": {
"input": "$booking",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.delivery_date", id ] },
"$$el",
false
]
}
}
},
[false]
]
}
}
}
];
RegisterList.aggregate(pipeline, function(err, docs){
if(err) throw err;
res.json(docs);
});
});
The $ projection operator projects only first matching element, refer here
Project all subdocuments {bookings: 1},then filter subdocuments within your application.

Elasticsearch: how to store all json objects dynamically

I'm trying to store all Json objects through elasticsearch.
client.create({
index: 'index',
type: 'type',
id:"1"
body:result[0]
},function (error,response)
{
if (error)
{
console.log('elasticsearch cluster is down!');
}
else
{
console.log('All is well');
}
});
In this result[0] I'm getting my first value of a Json object but I need to store all Json objects dynamically.
The output which i'm getting is:
-> POST http://localhost:9200/index/type/1?op_type=create
{
"Name": "Martin",
"Age": "43",
"Address": "trichy"
}
<- 201
{
"_index": "index",
"_type": "type",
"_id": "1",
"_version": 4,
"created": true
}
But I need an output like this:
-> POST http://localhost:9200/index/type/1?op_type=create
{
"Name": "Martin",
"Age": "43",
"Address": "trichy"
},
{
"Name": "vel",
"Age": "23",
"Address": "chennai"
},
{
"Name": "ajay",
"Age": "23",
"Address": "chennai"
}
<- 201
{
"_index": "index",
"_type": "type",
"_id": "1",
"_version": 4,
"created": true
}
What you need is to use the bulk endpoint in order to send many documents at the same time.
The body contains two rows per document, the first row contains the index, type and id of the document and the document itself is in the next row. Rinse and repeat for each document.
client.bulk({
body: [
// action description
{ index: { _index: 'index', _type: 'type', _id: 1 } },
// the document to index
{ Name: 'Martin', Age: 43, Address: 'trichy' },
{ index: { _index: 'index', _type: 'type', _id: 2 } },
{ Name: 'vel', Age: 23, Address: 'chennai' },
{ index: { _index: 'index', _type: 'type', _id: 3 } },
{ Name: 'ajay', Age: 23, Address: 'chennai' }
]
}, function (err, resp) {
// ...
});
I suspect your result array is the JSON you get from your other question from yesterday. If so, then you can build the bulk body dynamically, like this:
var body = [];
result.forEach(function(row, id) {
body.push({ index: { _index: 'index', _type: 'type', _id: (id+1) } });
body.push(row);
});
Then you can use the body in your bulk call like this:
client.bulk({
body: body
}, function (err, resp) {
// ...
});