I have a JSON file like this:
{
"level1": [
{},
{},
{
"level2": {
"level3": [
[
{
"second": 0
}
],
[
{
"second": 1,
"label": "A",
"frame": 40
}
],
[
{
"second": 2,
"label": "A",
"frame": 60
},
{
"second": 2,
"label": "B",
"frame": 60
}
],
[
{
"second": 3,
"label": "B",
"frame": 90
}
]
]
}
}
]
}
I would like to find the elements A and B when they occur contemporarily in the same second. I'm able to find label "A" or label "B" but I would like that the result of the query is second 2 or a list of all seconds when both elements appear.
Related
I'm starting to study mongodb, but I want to understand better when to use embedded or referenced documents.
the project I'm trying to make is something similar to a POS (point of sale), working like:
Every time that someone make a purchase, it inserts on the database, but, there are costumers with N groups of stores and theses "groups of stores" have N stores and N POS.
After this i want a database to update the prices in specific stores (not in groups) and make a summary of how many sales any POS made.
So, talking about perfomance what is the best design and why?
here are some exemples that I made:
Embedded :
{
"group1": [
{
"store_id": 1,
"store1": "store_name",
"POS": [
{
"id_POS": 1,
"POS_name": "name_1",
"purchases": [
{
"id": 1,
"date": "2022_10_05",
"time": "10:00:00"
},
{
"id": 2,
"date": "2022_10_05",
"time": "10:10:00"
}
]
},
{
"id_POS": 2,
"POS_name": "name_2",
"purchases": [
{
"id": 1,
"date": "2022_10_05",
"time": "10:50:00"
},
{
"id": 2,
"date": "2022_10_05",
"time": "11:59:00"
}
]
}
],
"itens": [
{
"id_prod": 4,
"prod_name": "avocado",
"price": 2.5
},
{
"id_prod": 5,
"prod_name": "potato",
"price": 1.5
}
]
}
]
}
Referenced:
group of stores,POS, and itens collection:
{
"group1":{
"stores":[
{
"store_id":1,
"name":"store1",
"POS":[
{"POS":[
{"id_pos":1},
{"id_pos":2}
]}
],
"itens":[
{"id_prod":4},
{"id_prod":5}
]
}
]
}
}
{
"id_pos": 1,
"id_store": 1,
"purchases": [
{
"id": 1,
"date": "2022_10_05",
"time": "10:50:00"
},
{
"id": 2,
"date": "2022_10_05",
"time": "11:59:00"
}
]
}
{
"id_store": 1,
"itens":[{
"id_prod": 4,
"prod_name": "avocado",
"price": 2.5
},
{
"id_prod": 5,
"prod_name": "potato",
"price": 1.5
}]
}
Playground:https://mongoplayground.net/p/YUV_fReyGsr
I have following query. I need to combine the result 2 by 2. Meaning I need to combine facet "1","2" as a result and facet "3","4" as another result. It's guaranteed that the number of facet will be even. Also, each pair of facet should get at most one record(it might not matter)
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
}
])
The expected result will be
[
{
"1": [
{
"ID": "1",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]
I was able to figure this out using $concatArrays operator, along with $project.
Live demo here
Database
[
{
"ID": "1",
"attr1": "123",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
]
},
{
"ID": "4",
"attr1": "123",
"array": [
{
"ID": "5",
"attr1": "456"
}
]
}
]
Query
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
},
{
"$project": {
_id: 0,
"1": {
"$concatArrays": [
"$1",
"$2"
]
},
"2": {
"$concatArrays": [
"$3",
"$4"
]
}
}
}
])
Result
[
{
"1": [
{
"ID": "1",
"_id": ObjectId("5a934e000102030405000000"),
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"_id": ObjectId("5a934e000102030405000001"),
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]
My data looks something like that:
[
{
"_id": 1,
"members": [
{
"id": 1,
"name": "name_1",
"assigned_tasks": [
1,
2,
3
]
},
{
"id": 1,
"name": "name_2",
"assigned_tasks": [
1
]
}
],
"tasks": [
{
"id": 1,
"name": "task_1",
},
{
"id": 2,
"name": "task_2",
},
{
"id": 3,
"name": "task_3",
}
]
}
]
I have a collection that represents a "class" which contains a list of members and a list of projects.
Each member can be assigned to multiple projects.
I wanna be able to count the number of members assigned to each of the tasks in the results and add it as a new field like:
[
{
"_id": 1,
"members": [
{
"id": 1,
"name": "name_1",
"assigned_tasks": [
1,
2,
3
]
},
{
"id": 1,
"name": "name_2",
"assigned_tasks": [
1
]
}
],
"tasks": [
{
"id": 1,
"name": "task_1",
"number_of_assigned_members":2
},
{
"id": 2,
"name": "task_2",
"number_of_assigned_members":1
},
{
"id": 3,
"name": "task_3",
"number_of_assigned_members":2
}
]
}
]
How can I create that query?
You can use $map and than $reduce,
$map tasks through object by object check in $reduce on members, if assigned_tasks is available or not, if available then add 1 otherwise 0,
db.collection.aggregate([
{
$addFields: {
tasks: {
$map: {
input: "$tasks",
as: "t",
in: {
$mergeObjects: [
"$$t",
{
number_of_assigned_members: {
$reduce: {
input: "$members",
initialValue: 0,
in: {
$cond: [
{ $in: ["$$t.id", "$$this.assigned_tasks"] },
{ $add: ["$$value", 1] },
"$$value"
]
}
}
}
}
]
}
}
}
}
}
])
Playground
I want to find closest result from array inside document for every doc, and project it new object using MongoDB. It will be easier to explain what I trying to do by example:
Doc schema:
{
"id": "string",
"name": "string",
"track" : [
{
"time": "number",
"distance": "number"
}
]
}
EXAMPLE:
I want to find closest results for every doc for time equals 4
Input data:
[
{
"id": "1",
"name": "test1",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 17
},
{
"time": 4,
"distance": 23
},
{
"time": 6,
"distance": 33
}
]
},
{
"id": "2",
"name": "test2",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 2,
"distance": 12
},
{
"time": 4,
"distance": 26
},
{
"time": 6,
"distance": 32
}
]
},
{
"id": "3",
"name": "test3",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 12
}
]
}
]
Output data:
[
{
"id": "1",
"result" : {
"time": 4,
"distance": 23
}
},
{
"id": "2",
"result" : {
"time": 4,
"distance": 26
}
},
{
"id": "3",
"result" : {
"time": 3,
"distance": 12
}
}
]
Is it possible to do this using MongoDB?
db.collection.aggregate([
{
"$addFields": {
"tracks": {
"$filter": {
"input": "$track",
"as": "track",
"cond": {
"$lte": [
"$$track.time",
4
]
}
}
}
}
},
{
"$addFields": {
"tracks": {
"$slice": [
"$tracks",
-1
]
}
}
},
{
"$unwind": "$tracks"
},
{
"$project": {
"tracks": 1,
"name": 1
}
}
])
Play
It does below things:
Finds whose track time is <=4 and adds it to an array called items
Then it gets the last element - i.e closer element
Take the element from array - unwind
Projects what is needed.
I want to aggregate data for the following sample array.
[
{
"_id": "5b7c0540342100091a375793",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionThird",
"id": 2,
"value": [
10,
50,
20
]
}
]
}
]
},
{
"_id": "5b3cd546342100514b4683a2",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
19,
5,
8
]
},
{
"name": "sectionThird",
"id": 2,
"value": [
60
]
}
]
},
{
"name": "EFGH",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
5
]
},
{
"name": "sectionThsads",
"id": 2,
"value": [
8
]
}
]
}
]
}
]
I want the following output:
[
{
"page": "ABCD",
"sections": [
{
"name": "sectionThird",
"totalValue": 140
},
{
"name": "sectionFourth",
"totalValue": 32
}
]
},
{
"page": "EFGH",
"sections": [
{
"name": "sectionFourth",
"totalValue": 5
},
{
"name": "sectionThsads",
"totalValue": 8
}
]
}
]
In the above sample array, you can see there are multiple documents with "page" as one of the keys which are also an array of objects. Each page object has a key "name" which is going to be unique for each object in "page" array. The "page" object has "sections" key and they also have "name" key in them which is going to be unique for each object.
So the output array is grouped by page.name then in that its grouped by sections.name from all the page objects with the sum of all the value array throughout sections inside a page object with the same section name.
You can use below aggregation.
$unwind each page and section followed by $group with $sum to sum the values for each section and $push to push the sections values back into page array.
db.col.aggregate([
{"$unwind":"$pages"},
{"$unwind":"$pages.sections"},
{"$group":{
"_id":{"pagename":"$pages.name","sectionname":"$pages.sections.name"},
"totalTime":{"$sum":{"$sum":"$pages.sections.value"}}
}},
{"$group":{
"_id":"$_id.pagename",
"sections":{"$push":{"name":"$_id.sectionname","totalTime":"$totalTime"}}
}}])