addToSet mongoDB not adding if one value is repeated - javascript

I have the following collection in MongoDB
[
{
"acronym": "front",
"references": [
{
"date": "2020-03-04",
"value": "5.6"
},
{
"date": "2020-03-05",
"value": "6.3"
}
]
}
]
I want to use the function $addToSet in order to add new document into references. I know that it can be done with the following code:
db.collection.update({
"acronym": "front"
},
{
$addToSet: {
"references": {
"date": "2020-03-06",
"value": "6"
}
}
})
And it will add the new document to the array references, so the result is the following:
[
{
"acronym": "front",
"references": [
{
"date": "2020-03-04",
"value": "5.6"
},
{
"date": "2020-03-05",
"value": "6.3"
},
{
"date": "2020-03-06",
"value": "6"
}
]
}
]
QUESTION: What I want to obtain is that in the case of adding a date that is already in the array, the update will no be produced.
Here is the playground: https://mongoplayground.net/p/DPER2RuROEs
Thanks!

You can add another qualifier to the update to prevent duplicated dates
db.collection.update({
"acronym": "front",
"references.date": {
$ne: "2020-03-04"
}
},
{
$addToSet: {
"references": {
"date": "2020-03-04",
"value": "6"
}
}
})
I got the solution from here

Related

Getting second level nested object inside array of objects mongodb

My database looks like this:
[
{
"title": "man",
"articlesType": [
{
"title": "shoes",
"articles": [
{
"title": "shoes1",
"id": "randomId"
},
{
"title": "shoes2",
"id": "alsoRandomId"
}
]
}
]
},
{
"title": "woman",
"articlesType": [
{
"title": "pants",
"articles": [
{
"title": "pants1",
"id": "anotherRandomId"
},
{
"title": "pants1",
"id": "justId"
}
]
}
]
}
]
I expect something like this: , is it possible to get whole object in this nested just using an ID?
{
"title": "shoes2",
"id": "alsoRandomId"
}
I found this, but does not work for me
You can try an aggregation pipeline using double $unwind to deconstruct the array twice and then filter by your desired id (I'm assuming you want to match by the id).
And the last step, $project is to output the result in the same way as you want.
db.collection.aggregate([
{
"$unwind": "$articlesType"
},
{
"$unwind": "$articlesType.articles"
},
{
"$match": {
"articlesType.articles.id": "alsoRandomId"
}
},
{
"$project": {
"title": "$articlesType.articles.title",
"id": "$articlesType.articles.id"
}
}
])
Example here

Mongo Organize by object inside aggregate request

My project is in nodeJs with express and i use mongoose for the request to my database mongoDb.
I have a model Media the structure is:
{
"_id": {
"$oid": "6354f982a11464ff4f7bac60"
},
"userId": {
"$oid": "6353aa119d39ccbb3263123f"
},
"date": "2022-10-23",
"base64": "data:image/png;base64,iVBORw0KGgoAAA....=",
"label": "Noamount",
"uriPath": "xxxx",
"s3Path": "xxxx",
"amount": 0,
"__v": 0,
"type": "tva"
}
Like you seen there is a field date, imagine that i have 3 medias on differents month:
{
"date": "2022-10-23",
"label": "monthTen",
"type" : "tva",
... // Other property
},
{
"date": "2022-09-10",
"label": "monthNineFirst",
"type" : "tva",
... // Other property
},
{
"date": "2022-09-19",
"label": "monthNineSecond",
"type" : "other",
... // Other property
}
I want to output something like this:
// Ordery by type in first place and by month
// number like 9 = the month inside the date property
{
tva: {
9: [{ label: "monthNineFirst"... }],
10: [{ label: "monthNineTen"... }]
},
other: {
9: [{ label: "monthNineSecond"... }]
}
}
Is found the property aggregate but i don't understand it correctly.
I know how to dow that in JS it's easy, but can i do that directly on the request with the property aggregate and $group?
There is what i have done so far https://mongoplayground.net/p/-vAbdnnqOfD
Here's one way to do it by extending your mongoplayground.net start.
db.collection.aggregate([
{ // group all docs by month
$group: {
_id: {
$month: {
$dateFromString: {
dateString: "$date",
format: "%Y-%m-%d"
}
}
},
data: {"$push": "$$ROOT"}
}
},
{ // group all groups into a single doc
"$group": {
"_id": null,
"groupData": {
"$push": {
// k,v for $arrayToObject
"k": "$_id",
"v": {
"$sortArray": {
"input": "$data",
"sortBy": {"date": 1}
}
}
}
}
}
},
{
"$replaceWith": {
"$arrayToObject": {
"$map": {
"input": {
// sort by month
"$sortArray": {
"input": "$groupData",
"sortBy": {"k": 1}
}
},
"in": {
"$mergeObjects": [
"$$this",
{ // rewrite k as string
"k": {"$toString": "$$this.k"}
}
]
}
}
}
}
}
])
Try it on mongoplayground.net.

mongodb: How to use variable inside group operator in aggregate operation?

I am tring to make a query where use the value and try to interpolate a string in a new field.
Mongo Database:
[
{
"state": "1",
"events": {
"1": [
{
"date": 123.2,
"msg": "msg1"
},
{
"date": 124.2,
"msg": "msg2"
}
],
"2": [
{
"date": 125.2,
"msg": "msg3"
},
{
"date": 126.2,
"msg": "msg4"
}
],
}
},
{
"state": "2",
"events": {
"1": [
{
"date": 123.2,
"msg": "msg1"
},
{
"date": 124.2,
"msg": "msg2"
}
],
"2": [
{
"date": 125.2,
"msg": "msg3"
},
{
"date": 126.2,
"msg": "msg4"
}
],
}
}
]
Aggregate query:
db.collection.aggregate({
"$match": {
"state": {
"$in": [
"1",
"2"
]
}
}
},
{
"$group": {
"_id": {
"state": "$state"
},
"this_path": {
"$first": {
"$concat": [
"events.",
"$state",
".0.date"
]
}
}
}
})
"this_path" gets "events.1.0.date", but how to use this value, in another query(line), I would like to do like a string interpolation. Some thing like
...
"date": {
"$first": { `\$${this_path}`}
...
so it become the "events.1.date" then "$events.1.0.date" then "123.2"
you can define it by let just for example a fragment from pipeline:
$lookup: {
from: contentCollectionName,
as: 'content',
let: {
parentId: '$id',
},
The id is taken from above matched documents, but it can be anything

JSON group by key value to new JSON Javascript

I have been reading some posts which are related to my question, whereas I have not been able to find a proper solution for what I'm trying to do hear.
I have this JSON file that I am obtaining directly from my database via a sql query:
[
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-21",
"price": 14.173041264216105
}
]
},
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
}
]
My objectif is to be able to sort/transform this json object to a new json object which is classified by the scenario, so, something that looks like:
[
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-21",
"price": 14.173041264216105
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
I have been trying some javascript selfmade functions but I have not obtainend the desired result.
This is the last thing I've tried:
let estructura = [];
for (var j =0; j<obj.length; j++){
for (var i=0; i<estructura.length; i++){
if(obj[j]['scenario'] == estructura[i]['scenario']){
estructura[i]['data'].push(obj[j]['data'])
} else {
console.log("no match, we add the scenario to estructura")
estructura.push(
{
scenario:obj[j]['scenario'],
data: []
})
}
}
}
Thank you
You can achieve this easily with built-in functions like reduce. Iterate over the input, grouping into an object indexed by scenario, creating a object with a data array if the scenario doesn't exist yet, and push to that array:
const input=[{"scenario":"scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18","data":[{"date":"2018-05-21","price":14.173041264216105}]},{"scenario":"scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99","data":[{"date":"2018-05-22","price":42.94691197077433}]}]
console.log(
Object.values(input.reduce((a, { scenario, data }) => {
if (!a[scenario]) a[scenario] = { scenario, data: [] };
a[scenario].data.push(data[0]);
return a;
}, {}))
);

Filtering subarray of objects

I need to filter a subarray of elements.
var university = {
"fax": "123345",
"email": "test#test.com",
"url": "www.test.com",
"classes": [
{
"number": "1",
"name": "maths",
"students": [
{
"name": "Max",
"exams": [
{
"date": "2016-01-04T18:32:43.000Z",
"passed": false
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": true
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": false
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": true
}
]
},
{...}
]
},
{...}
]
}
Ok I need to get all the classes without filtering, all the students of each class without filtering, but in the exams array I only need to get the ones that passed.
I tried the following:
university.classes.students.exams.filter(function (el) {
return el.passed
});
But it is not working...
I've googled a solution to this without success...any help would be appreciated.
classes and students are arrays - so you have to loop those as well:
university.classes.forEach(function(uniClass) {
uniClass.students.forEach(function(student) {
student.exams = student.exams.filter(function (el) {
return el.passed;
});
});
});

Categories