Mongodb aggregate - using $addFields inside a nested array to get true/ false - mongodb

I've been trying to get data back with an additional field inside a nested array using $addFields.
The data is:
{
"show_id": 1,
"ext1_id": 126790,
"ext2_id": 44275,
"show_title": "Some Big title name",
"poster_url": "https://cdn.something.com/media/cover/o65bBCMVI.jpg",
"description": "show description",
"year": 2021,
"episodes": [
{
"episode_title": "episode title 1",
"episode_number": "01",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADKWGOO8WclqGSBG6Kdy0DkRTAbLgGAALMAgACvj7BVnkS-frrNBz8HgQ",
"unique_id": "AgADzAIAAr4-wVY",
"message_id": 41,
"added_by": "bot",
"watched_by": [919205468, 1778357657],
"timestamp": "2021-11-12T15:32:46.172302"
},
{
"episode_title": "Episode title 2",
"episode_number": "02",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADKmGOO9QAAZCDz6lonoW1R5zPUM9sVAACOAQAApgFAVdhA3c9xoF0oB4E",
"unique_id": "AgADOAQAApgFAVc",
"message_id": 42,
"added_by": "bot",
"watched_by": [919205468],
"timestamp": "2021-11-12T15:33:01.053049"
},
{
"episode_title": "episode title 3",
"episode_number": "03",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADK2GOO9zX4pgK7d1ERd5BeQkvvobSAAKaBAAC2tNJVwYVsJ_OGprTHgQ",
"unique_id": "AgADmgQAAtrTSVc",
"message_id": 43,
"added_by": "bot",
"watched_by": [919205468],
"timestamp": "2021-11-12T15:33:08.862887"
}
],
"alt_titles": ["alt title", "ALT TITLE", "Alt-Title"],
"is_airing": true,
"added_by": "bot",
"timestamp": "2021-11-12T15:32:45.298797"
}
So basically, what I was trying was to add a field user_watched inside the episodes list so that it'll just return True / False by checking if the user_id is present in the watched_by list which is again inside the episodes list.
I also didn't want the watched_by to be retured in the result.
I expected something like this:
{
"show_id": 1,
"ext1_id": 126790,
"ext2_id": 44275,
"show_title": "Some Big title name",
"poster_url": "https://cdn.something.com/media/cover/o65bBCMVI.jpg",
"description": "show description",
"year": 2021,
"episodes": [
{
"episode_title": "episode title 1",
"episode_number": "01",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADKWGOO8WclqGSBG6Kdy0DkRTAbLgGAALMAgACvj7BVnkS-frrNBz8HgQ",
"unique_id": "AgADzAIAAr4-wVY",
"message_id": 41,
"added_by": "bot",
"user_watched": true,
"timestamp": "2021-11-12T15:32:46.172302"
},
{
"episode_title": "Episode title 2",
"episode_number": "02",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADKmGOO9QAAZCDz6lonoW1R5zPUM9sVAACOAQAApgFAVdhA3c9xoF0oB4E",
"unique_id": "AgADOAQAApgFAVc",
"message_id": 42,
"added_by": "bot",
"user_watched": true,
"timestamp": "2021-11-12T15:33:01.053049"
},
{
"episode_title": "episode title 3",
"episode_number": "03",
"version": null,
"file_id": "BAACAgUAAx0EYN2eLQADK2GOO9zX4pgK7d1ERd5BeQkvvobSAAKaBAAC2tNJVwYVsJ_OGprTHgQ",
"unique_id": "AgADmgQAAtrTSVc",
"message_id": 43,
"added_by": "bot",
"user_watched": true,
"timestamp": "2021-11-12T15:33:08.862887"
}
],
"alt_titles": ["alt title", "ALT TITLE", "Alt-Title"],
"is_airing": true,
"added_by": "bot",
"timestamp": "2021-11-12T15:32:45.298797"
}
I tried this following code in pymongo:
db.data_col.aggregate([
{'$sort' : { 'timestamp' : -1 } },
{'$facet' : {
"metadata": [ { "$count": "total" } ],
"data": [
{'$addFields': {
'episodes.user_watched':
{'$cond': [
{
'$in': [
919209968,
"$episodes.watched_by"
]
},
True,
False
]
}
}},
{ "$skip": offset }, { "$limit": limit },
{ '$project' : {"episodes.watched_by":0} } ,
]
}}
])
but I got every user_watched fields False even if the user_id is present among the watched_by list.
and the returned data.

Query
map on episodes, check if the user(1778357657) in in the watched_by array and add the field true/false
removed the field watched_by
*your query looks different i guess you do more things, but this produces the expected output
*your code didn't work because "$episodes.watched_by", is an array that contains all the watched_by arrays, with $map each array is checked separately.
PlayMongo
aggregate(
[{"$set":
{"episodes":
{"$map":
{"input": "$episodes",
"in":
{"$mergeObjects":
["$$this",
{"user_watched":
{"$in": [1778357657, "$$this.watched_by"]}}]}}}}},
{"$set": {"episodes.watched_by": "$$REMOVE"}}])

Related

How to handle tags and hierarchies in ag-grid table data structure?

I would like to use the pivot feature, but since my data has a lot of tags (1-level nested), I'm not sure how to make ag-grid parse this data and recognize it.
Here's the data for example:
[
{
"_id": "1",
"symbol": "sym1",
"open_date": "2019-04-23",
"_type": "t1",
"currency": "USD",
"quantity": 456,
"tags": [
{
"tag": "G_TAG1",
"group_name": "Group_1",
},
{
"tag": "G_TAG2",
"group_name": "Group_1",
}
],
},
{
"_id": "2",
"symbol": "sym2",
"open_date": "2029-01-11",
"_type": "t2",
"currency": "EUR",
"quantity": 312,
"tags": [
{
"tag": "G3_TAG-ABC",
"group_name": "Group_3",
},
{
"tag": "G2_TAG-DEF",
"group_name": "Group_2",
},
{
"tag": "G_TAG3",
"group_name": "Group_1",
}
],
},
{
"_id": "3",
"symbol": "sym3",
"open_date": "2010-12-01",
"_type": "t3",
"currency": "AUD",
"quantity": 123,
"tags": [
{
"tag": "G_TAG3",
"group_name": "Group_1",
}
],
}
]
In columnDefs, I defined tags column like this:
{field:'tags',
enablePivot: true,
children: [
{
headerName: "Tag", valueGetter: params => params.data.tags.map(x => x.tag),
enablePivot: true,
},
{
headerName: "Tag Group", valueGetter: params => params.data.tags.map(x => x.group_name),
enablePivot: true,
},
]
},
Each data point has a list of tags and each tag can belong to a group or not. So the top-most hierarchy is the tag group and below that are the individual tags.
Is there a way aggrid can recognize this or a way I can transform the data so visualize per-tag or per-group statistics? For example, can I view stats grouped by tag group > tag > symbol?

how to push a data into an array of objects in mongodb based on the name into the the completed array in the breakfast array how will it be done?

I want to add a current date into a user meal plan breakfast and find
the name of an object like a banana on condition and add a date to the
completed array?
this is the mongoose document .every food item contains an array of completed and every time a request is sent it will add or remove date on the completed array. i should be able to push date to the completed array
{
"_id": {
"$oid": "616f193e9eb4ca14afc47fa8"
},
"date": {
"$date": "2021-10-19T15:52:09.298Z"
},
"email": "john#live.com",
"firstName": "john",
"lastName": "doe",
"password": "$2b$10$jKylT8MKsUl7ZS03EVi7SecQ1eWuB37J5rLVTU/C8VXBwkWQQo6EK",
"role": "user",
"token": "eyJhbGciOiJIQb-JA2kcKxWquDaM",
"mealplan": {
"dietType": ["Halal", "Vegetarian", "Vegan"],
"religionType": ["Agnostic", "Muslim", "Christian", "Buddhist"],
"ethinicType": ["Asian", "Native American"],
"_id": "6179a178ba48312626059d44",
"name": "first meal",
"budget": 2000,
"orac": 163,
"medicinal": 0,
"breakfast": [
{
"type": "breakfast",
"completed": [],
"fdcId": 1103194,
"name": "Carrots, raw, salad",
"numbers": 1,
"unit": "100 grams",
"recurring": {
"startTime": "08:30",
"endTime": "09:30",
"startDate": "2021-10-28",
"endDate": "2021-11-03",
"daysofweek": []
}
},
{
"type": "breakfast",
"completed": [],
"name": "orange juice",
"numbers": 1,
"unit": "100 mililiters",
"recurring": {},
"orac": 10,
"medicinal_value": 0,
"nutrition": []
},
{
"type": "breakfast",
"name": "banana",
"completed": [],
"numbers": 1,
"unit": "100 grams"
}
]
},
"__v": 0
}
when I send a post request it will be the name of the food and date.
date show be added to the completed array in name of food
use arrayFilter like this
for example we want add to food with name of bnana
db.collection.update({},
{
$push: {
"mealplan.breakfast.$[arr].completed": "date" // put date here
}
},
{
arrayFilters: [
{
"arr.name": "banana" // name of food here
}
]
})
https://mongoplayground.net/p/lbzcF0YPuDF

random document aggregate by two or more fields

I have questions list and they have structure like this:
{
"_id": {
"$oid": "5a077c418fdf294df73bf7ea"
},
"author": "PinkyaRabbit",
"question": "Что здесь литерал: var x = {};",
"category": "Javascript шаблоны",
"answers": [
"var x",
"{}",
"var x = {};",
"Нету тут его"
],
"real": "{}",
"description": "Литерал, это нейкое чистое значение, которое встречается в коде. Цифра, слово, объект - что угодно",
"users": [
{
"status": "good",
"wasToday": true,
"user": 471317129
}
],
"blockedBy": [],
"date": "2017-11-12T01:40:01+03:00"
}
I need to pick one random, question for user. Each user have personal categories list. blockedBy its an array if user dont want to take. I pick personal categories list like array user.categories and try to make aggregate request.
TGquestions.aggregate([
{ $match: {
users:{
"status": "clear",
"wasToday": false,
"user": chatid
},
category: { $in: user.categories },
blockedBy: { $ne: chatid}
}},
{ $sample: { size: 1 } }
], (err, qq) => {
The problem is that looks like my random not working atall. For example, first picked question from category with name "Javascript", next will be same from "Javascript", and white question not ends all next will be from this category. When question in this category ends, with next category same problem. The worst in this is that queue of categories each time same. So my random aggregate totaly failed. How to fix this?
upd. example
I have a user
{
"_id": {
"$oid": "5a15aa31457bca063c01248b"
},
"chatid": 213229659,
"username": "iamRB01",
"baned": false,
"name": "Rina",
"categories": ["Javascript", "Java"],
}
And some questions from some categories. I changed _id's to make all more readable.
{
"_id": "1",
"author": "PinkyaRabbit",
"question": "Что здесь литерал: var x = {};",
"category": "Javascript",
"answers": [
"var x",
"{}",
"var x = {};",
"Нету тут его"
],
"real": "{}",
"description": "Литерал, это нейкое чистое значение, которое встречается в коде. Цифра, слово, объект - что угодно",
"users": [
{
"status": "clear",
"wasToday": false,
"user": 213229659
}
],
"blockedBy": [],
"date": "2017-11-12T01:40:01+03:00"
},
{
"_id": "2",
"author": "PinkyaRabbit",
"question": "Первым признаком конструктора является?",
"category": "Javascript",
"answers": [
"слово new",
"метод construct",
"имя пишется с большой буквы",
"возможно обращение через this"
],
"real": "имя пишется с большой буквы",
"description": "Если имя чего-то пишется с большой буквы в Javascript, то это конструктор (если код писал не криворукий рак)",
"users": [
{
"status": "clear",
"wasToday": false,
"user": 213229659
}
],
"blockedBy": [],
"date": "2017-11-13T16:20:50+03:00"
},
{
"_id": "3",
"author": "Xiroho",
"question": "Для записи пятеричной системы счисления используются цифры -",
"category": "Java",
"answers": [
"01234",
"0123456789",
"01",
"10"
],
"real": "01234",
"description": "",
"users": [
{
"status": "clear",
"wasToday": false,
"user": 213229659
}
],
"date": "2017-11-20T23:31:03+03:00",
"blockedBy": []
},
{
"_id": "4",
"author": "PinkyaRabbit",
"question": "Как проверить, есть ли элемент в массиве",
"category": "Javascript",
"answers": [
"сделать цикл с проверкой if(haystack[i]===needle){return true;}",
"использовать проверку через filter",
"использовать функцию indexOf",
"использовать функцию includes"
],
"real": "использовать функцию includes",
"users": [
{
"status": "clear",
"wasToday": false,
"user": 213229659
}
],
"description": "Хотя indexOf работает верно\nif(array.indexOf(\"test\") > -1){ result++; }\nона проигрывает includes по быстродействию\narray.includes(\"test\")\nпоэтому стоит использовать includes. Тем не менее, не все браузеры поддерживают includes, которая появилась только в 2016 году, поэтому indexOf знать тоже надо",
"blockedBy": [213229659],
"date": "2017-12-01T01:21:09+03:00"
}
I want to pick one random question of this collection. For example first id=2, next with id 3, next with id 1 but not with id 4 cuz user turned off this question. But in my script looks like aggregate random not working... =(
The answer was that in nested arrays for picking real results needed to use $elemMatch.
TGquestions.aggregate([
{ $match: {
category: { $in: user.categories },
users: {
$elemMatch: {
"status": "clear",
"wasToday": false,
"user": chatid
}},
blockedBy: { $ne: chatid}
}},
{ $sample: { size: 1 } }
], (err, qq) => {

Spring data mongodb hierarchy

I have a nested json object in a hierarchical structure as defined below
[
{
"categoryId": 1,
"categoryName": "Category 1",
"childCategory": null,
"active": false
},
{
"categoryId": 2,
"categoryName": "Category 2",
"active": true,
"childCategory": [
{
"categoryId": 4,
"categoryName": "Category 4",
"childCategory": null,
"active": false
},
{
"categoryId": 5,
"categoryName": "Category 5",
"childCategory": null,
"active": true
}
]
},
{
"categoryId": 10,
"categoryName": "Category 10",
"childCategory": null,
"active": true
}
]
From this I want to select all the active categories to a single array structure. My output should be
[
{
"categoryId": 2,
"categoryName": "Category 2",
"active": true
},
{
"categoryId": 5,
"categoryName": "Category 5",
"active": true
},
{
"categoryId": 10,
"categoryName": "Category 10",
"active": true
}
]
Is it possible to directly fetch this data in a single query statement. I am using spring data for mongodb.
You can try below aggregation.
$redact to go through a document level at a time and perform $$DESCEND and $$PRUNE on the matching criteria.
$unwind the $childCategory with preserveNullAndEmptyArrays to keep the array with null values.
db.collection.aggregate({
$redact: {
$cond: [{
$eq: ["$active", true]
}, "$$DESCEND", "$$PRUNE"]
}
}, {
$unwind: {
path: "$childCategory",
preserveNullAndEmptyArrays: true
}
})

Update embedded object array inside array in MongoDB

I have a document like :
{
"_id": "1000",
"answer_count": 0,
"answer_order": 0,
"fields": [{
"name": "client_name",
"id": "com28",
"title": "Client",
"required": true,
"instruct": "",
"dateType": "text"
}, {
"name": "id_radio",
"id": "com26",
"title": "hobby",
"required": false,
"instruct": "",
"value": [{
"name": "Please select",
"selected": true,
"lid": "-1",
"defaultTip": true
}, {
"name": "option1",
"selected": false,
"lid": "0"
}, {
"name": "option2",
"selected": false,
"lid": "1"
}, {
"name": "option3",
"selected": false,
"lid": "2"
}]
}]
}
I try:
db.survey_stat.update({
"fields.id" : "com26",
"fields.value.name":"option1"
},
{
"$inc":{
"fields.0.value.$.selected_count":1
}
})
But it doesn't update any field. How can I incr the specific field inside a array ?
The array-entry with fields.id: "com26" which you want to change is fields.1 not fields.0. This means you are trying to change the wrong entry of the fields array.
Unfortunately the $-placeholder can only be used once in a field-path. When you have two nested arrays, it won't work. There is an open bugtracker ticket about this issue. The only workaround is to retrieve and replace the whole array-entry in which the nested field occurs.