Value update if object exist and create if not under array mongodb - javascript

I have a dataset like this:
[
{
"createdate": "2020-06-03T18:30:00.000Z",
"hold": [
{
"time": "12:30",
"user": [
"5ed8ae4891501a1c10246dfe"
]
},
{
"time": "13:00",
"user": [
"5ed8ae4891501a1c10246dfe"
]
},
{
"time": "13:30",
"user": [
"5ed8ae4891501a1c10246dfe"
]
}
],
"_id": "5ed745c38b4d8646601bad1d",
"__v": 0
},
{
"createdate": "2020-06-04T18:30:00.000Z",
"hold": [
{
"time": "12:30",
"user": [
"5ed8ae4891501a1c10246dfe"
]
},
{
"time": "13:00",
"user": [
"5ed8ae4891501a1c10246dfe"
]
},
{
"time": "13:30",
"user": [
"5ed8ae4891501a1c10246dfe"
]
}
],
"_id": "5ed745c3404a701fb888e732",
"__v": 0
}
]
Now I want to update some data on these two enteries, let's say I have to update "13:00" on both the enteries to push 5ed8ae4891501a1c10246dfe, and create/push new object "14:30" with user id i.e 5ed8ae4891501a1c10246dfe.
Also check if id already exist on user array then don't perform anything.
userdata = [{"startdate": "2020, 6, 4", "enddate": "2020, 6, 4", "time": ["12:30", "13:00","13:30"]}]
userdata is the data which we have to update on collection.
What I tried is like:
let userdata = [{ "startdate": "2020, 6, 4", "enddate": "2020, 6, 5", "time": ["12:30", "13:00", "13:30"] }]
const test = async () => {
try {
// I am Using mongoose, so CollectionName is dummy name to share
let data = [];
let getCalenderData = await CollectionName.find(
{ createdate: { $gte: new Date(userdata[0].startdate), $lte: new Date(userdata[0].enddate) } }
).exec();
console.log(getCalenderData)
if (getCalenderData.length > 0) {
data = getCalenderData;
}
console.log(JSON.stringify(data, null, 3))
// So here what I tried to achieve is first on one query pull all data,
// then using filter function to segregate the data,
// then after this set push or pull the data at single query.
} catch (error) {
console.log(error)
}
}
test();
But I have confusion that this approach would be little lengthier than Database query. We have tan option to solve this through javascript but in terms of Database there must me some smart query which perform all these task in a few lines rather than using the Javascript.
Any expert of MongoDB Database, please suggest me how to perform this through DB Query rather than javascript. Any help from the experts will be really really appreciated. Thanks in Advance

Related

update nested array data in mongodb and node js

I want to update status in corder data. i try many time but i cannot update that data. if you know how update that data ??
{
"_id": "63064232cf92b07e37090e0a",
"sname": "Bombay collection ",
"name": "Hussain Khan",
"costomer": [
{
"cname": "Basan",
"cphone": 9863521480,
"_id": "632eeff2a9b88eb59d0210f0",
"corder": [
{
"clothType": "Shirt",
"date": "2022-10-21",
"status": "false",
"_id": "635283363edde6a0e9e92dc0"
},
]
}
]
}
You can use $[<identifier>]. For example:
db.collection.update(
{},
{$set: {"costomer.$[elemA].corder.$[elemB].status": newStatus}},
{arrayFilters: [
{"elemA._id": costomerId},
{"elemB._id": corderId}
]}
)
See how it works on the playground example

Need to get the average of complex data on mongodb

I'm not being able to find the average of a complex search in mongodb, using mongoose (nodejs) (and i'm not sure if its possible).
So, i have a collection of Scouts.
A Scout is basically the vote of a user for a player, in a match (fixture).
Scout items looks like this:
{
"_id": "6036dbbd148ccf17e82e6f14",
"player": "60243968d7ec0721344514ab",
"user": "601e9c826a339228e8f54305",
"fixture": "602435741f2e4e263492de66",
"score": 7,
"text": "Lorem ipsum",
"likes": 92,
"createdDate": "2021-02-24T23:05:33.176Z",
"__v": 0
},
{
"_id": "6036dbbd148ccf17e82e6f16",
"player": "60243968d7ec0721344514ab",
"user": "601e9c826a339228e8f54306",
"fixture": "602435741f2e4e263492de66",
"score": 1,
"text": "Lorem ipsum",
"likes": 76,
"createdDate": "2021-02-24T23:05:33.181Z",
"__v": 0
},
What i need is: the average score of a player in a fixture (among all users).
And this is what i'm trying:
Scout.aggregate([
{ $match: {
$and: [
{player: mongoose.Types.ObjectId(req.params.playerId)},
{fixture: mongoose.Types.ObjectId(req.params.fixtureId)},
]}
},
{ $group: { _id: "$_id", "avgScore": { "$avg": "$score" }}}
])
But all i get as result is this (which is not the expected result - should be 4 as the avg):
{
"_id": "6036dbbd148ccf17e82e6f16",
"avgScore": 1
},
{
"_id": "6036dbbd148ccf17e82e6f14",
"avgScore": 7
}
]
Your aggregation is okay but you are regrouping on document by _id which will always be different, so do this,
{
$group: {
_id: null,
"avgScore": {
"$avg": "$score"
}
}
}
Test it here: https://mongoplayground.net/p/6Qt8E69Z2d6

How to enhance a json object?

I am recieving a json object from an api as following:
[
{"id":998,
"client":{"id":"AF01072","name":"Vivek","lastName":"Joshi","phone":123},
"membership":{"type":"Semi-Annually","price":18000},
"start_date":"2019-11-19","end_date":"2020-05-16","payment":12000,"balance":0
},
{"id":1004,
"client":{"id":"AF01072","name":"Vivek","lastName":"Joshi","phone":123},
"membership":{"type":"Annually","price":30000},
"start_date":"2020-08-27","end_date":"2021-08-27","payment":30000,"balance":5000,
}
]
in angular when I loop to print the data 'client' information prints two times, because it is repeated two times.
<div *ngFor="let c of clientinfo">
{{c.client.name}}
{{c.membership.type}}
{{c.membership.price}}
{{c.start_date}}
{{c.end_date}}
.
.
.
</div>
How can I enhance this data so I get only client information once but the rest stay as they are?
thanks in advance
Whenever you need to group some data by some value you can use an object because object properties are guaranteed to never be duplicated. You have to be careful however because properties can be overwritten.
First, let's settle on a structure that works. The following is one such structure that can work:
{
[client.id] : {
client: client,
info : [
{ membership, start_date },
{ membership, start_date },
..
]
},
[client.id] : {
client: client,
info : [
{ membership, start_date },
{ membership, start_date },
..
]
},
..
}
There are other ways to arrange the data but the key is to exploit objects to implement a map/hash/associative array of key/value pairs. With this we can group the data from your array:
let group = {};
jsonData.forEach(x => {
// check if group already contain this client:
if (!group[x.client.id]) {
// auto-create array if does not exist
group[x.client.id] = {
client: x.client,
info: []
};
}
group[x.client.id].info.push({
membership: x.membership,
start_date: x.start_date
});
});
Now you have an object grouped by client id where each property is an object that has an info array that contains membership information.
If you need to loop over this data structure you can convert it back to an array by doing:
let groupArray = Object.values(group);
This will give you the following data structure:
[
{
client: client,
info : [
{ membership, start_date },
{ membership, start_date },
..
]
},
{
client: client,
info : [
{ membership, start_date },
{ membership, start_date },
..
]
},
..
]
An array of client objects with an info property containing an array of membership data. For your sample data it would be something like:
[
{
"client":{"id":"AF01072","name":"Vivek","lastName":"Joshi","phone":123},
"info": [
{
"membership":{"type":"Semi-Annually","price":18000},
"start_date":"2019-11-19",
"end_date":"2020-05-16",
"payment":12000,"balance":0
},
{
"membership":{"type":"Annually","price":30000},
"start_date":"2020-08-27",
"end_date":"2021-08-27",
"payment":30000,"balance":5000,
}
]
}
]
You need to create array of memberships for each client like below. And in the template file, you need to use two *ngFor loops. One to loop client details and another one to loop the respective client's membership details.
Working stackblitz
const result = [{
"id": 998,
"client": {
"id": "AF01072",
"name": "Vivek",
"lastName": "Joshi",
"phone": 123
},
"membership": {
"type": "Semi-Annually",
"price": 18000
},
"start_date": "2019-11-19",
"end_date": "2020-05-16",
"payment": 12000,
"balance": 0
},
{
"id": 1004,
"client": {
"id": "AF01072",
"name": "Vivek",
"lastName": "Joshi",
"phone": 123
},
"membership": {
"type": "Annually",
"price": 30000
},
"start_date": "2020-08-27",
"end_date": "2021-08-27",
"payment": 30000,
"balance": 5000,
},
{
"id": 1005,
"client": {
"id": "AF01073",
"name": "Some Other",
"lastName": "Joshi",
"phone": 123
},
"membership": {
"type": "Annually",
"price": 30000
},
"start_date": "2020-08-27",
"end_date": "2021-08-27",
"payment": 30000,
"balance": 5000,
}
].reduce((acc, item, i) => {
if (i == 0) {
acc.push(constructCorrectObject(item));
return acc;
}
let foundItem = acc.find(it => it.id === item.client.id);
if (foundItem) {
addMemeberShipDetails(foundItem, item);
return acc;
} else {
acc.push(constructCorrectObject(item));
return acc;
}
}, []);
function constructCorrectObject(item) {
return {
"id": item.client.id,
"name": item.client.name,
"lastName": item.client.lastName,
"phone": item.client.phone,
"membership": [{
"id": item.id,
"type": item.membership.type,
"price": item.membership.price,
"start_date": item.start_date,
"end_date": item.end_date,
"payment": item.payment,
"balance": item.balance,
}]
}
}
function addMemeberShipDetails(acc, item) {
acc.membership.push({
"id": item.id,
"type": item.membership.type,
"price": item.membership.price,
"start_date": item.start_date,
"end_date": item.end_date,
"payment": item.payment,
"balance": item.balance,
});
}
console.log(result);

Get minimum column value from related entity

Please, help me. I cant find information about how do this.
I have got this code. It load all products with all relations. One of relations is product item. In product item entity I have got price column.
How I can get minimal product item price without get in my response array of product items?
const { skip, take } = pagination;
const query = this.createQueryBuilder('product');
query.where('product.shop = :id AND product.blocked = FALSE', {
id: shop.id,
});
if (skip) {
query.offset(Number(skip));
}
if (take) {
query.limit(Number(take));
}
query.leftJoin('product.info', 'info');
query.leftJoin('product.avatar', 'avatar');
// load product items
query.leftJoin('product.productItem', 'item');
query.select([
'product.id',
'product.path',
'info.name',
'info.description',
'info.info',
'info.lang',
'avatar.path',
'avatar.type',
'item.price'
]);
const [list, amount] = await query.getManyAndCount();
Now i have got:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"productItem": [
{
"price": 1000
},
{
"price": 500
},
{
"price": 300
},
{
"price": 2000
},
{
"price": 3000
}
]
}
]
}
........
But I need:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"minProductItemPrice": 300
}
]
}
Pls help me
You can find the answer for this on Stackoverflow already.
Here is a similar question Typeorm select max with specific column
Basically, getManyAndCount() method that you are using is useful when fetching entities. In your case, you are trying to obtain an aggregate value encompassing multiple entities.
You need to make separate selection, like so
query.select("MIN(item.price)", "min");
and then get the result with
return query.getRawOne();

Sorting a nest object by datetime not working as expected

I am having some trouble sorting a nested object by its timestamp. I was hoping for some help...
This is what the object looks like and what I have so far...
useEffect(() => {
if (realtime.length) {
let unorderedmessage = realtime.concat(messages);
const orderedMessages = unorderedmessage
.slice()
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
setMessages(orderedMessages);
}
}, [realtime]);
[
Object {
"_id": "a16edcb7-17e1-46ea-b8ce-5ec312d5eb6c",
"createdAt": 2020-04-23T01:51:48.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "2–> Olivia to Mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "5ef28d42-6f7c-45eb-a5e1-59ca700f56b7",
"createdAt": 2020-04-23T02:01:52.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "4–> Olivia to mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "1e07873f-f010-4e9d-be17-9bcb7793695b",
"createdAt": 2020-04-23T02:02:06.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"lTONqS9O00PhkxwHD2EYs05EMwu2",
],
"text": "5–> mike to Olivia",
"user": Object {
"_id": "OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
"avatar": "123",
},
},
Object {
"_id": "5fecafc3-c608-4156-b88c-f6c57e8e9977",
"createdAt": 2020-04-23T02:01:20.000Z,
"index": 1,
"key": "cid-1710824786",
"receiver": Array [
"OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
],
"text": "3–> Olivia to Mike",
"user": Object {
"_id": "lTONqS9O00PhkxwHD2EYs05EMwu2",
"avatar": "123",
},
},
Object {
"_id": "fae07391-9968-432a-8a39-0c1be0d7e9ac",
"createdAt": 2020-04-23T01:51:41.000Z,
"index": 0,
"key": "cid-1710824786",
"receiver": Array [
"lTONqS9O00PhkxwHD2EYs05EMwu2",
],
"text": "1–> mike to Olivia",
"user": Object {
"_id": "OUloNoRKdIeyhNFcAAB6VLrZ5yH2",
"avatar": "123",
},
},
],
The messages are still coming in out of order so I am sure I am writing the sort function incorrectly. I am going through these tutorials and docs and it seems to be correct....
https://www.geeksforgeeks.org/sort-an-object-array-by-date-in-javascript/
https://flaviocopes.com/how-to-sort-array-by-date-javascript/
How to sort an array by a date property
I have also tried explicitly writing out the function like:
let unorderedmessage = realtime.concat(messages);
unorderedmessage.sort(function(a, b) {
return new Date(b.createdAt) - new Date(a.createdAt);
});
setMessages(unorderedmessage);
but still no luck. Can anyone see what I am doing wrong?
Works like a charm for me: https://playcode.io/583725/
Cannot be the issue in your Object variable definition?
You don't need to specify Object, this is enough:
const myNewObject = {firstKey: 'firstValue', secondKeys: 'secondValue'}
But if you do, you have to create it with new keyword:
const myNewObject = new Object {firstKey: 'firstValue', secondKeys: 'secondValue'}

Categories

Resources