push object into array field in document in mongoDb - arrays

Schema
{
userid:{type:String,required:true,unique:false},
products:[{
productid:{
type:String
},
quantity:{
type:Number,
default:1,
},
}],
}
existing document:
{
"_id": {
"$oid": "633a8a8a3cb2f7a3e9703261"
},
"userid": "633a8a833cb2f7a3e970325c",
"products": [
{
"productid": "633993d09725095d71b071db",
"quantity": 1,
"_id": {
"$oid": "633a8a8a3cb2f7a3e9703262"
}
}
],
"createdAt": {
"$date": {
"$numberLong": "1664780938934"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1664780938934"
}
},
"__v": 0
}
now i want to push below object to products array
"products":{productid:"6786879",quantity,2}
i tried below command (carts is collection name)
db.carts.update( { userid : "633a8a833cb2f7a3e970325c" },{ $push: { "products":
{productid:"6786879",quantity,2} } });
it throws below error :
clone(t={}){const r=t.loc||{};return e({loc:new Position("line"in r?
r.line:this.loc.line,"column"in r?r.column:......)} could not be cloned.
please anyone could help me

Related

MongoDB DeleteMany not deleting documents

So, when i run this query to delete some friend request documents:
db.friendRequests.deleteMany([
{
$and: [
{ author: ObjectId("636a88de3e45346191cf4257") },
{ friend_id: ObjectId("636faabb1861c5b8773f751e") },
],
},
]);
then it doesn't delete anything, and i dont know why.
Heres the friendRequests document exported as JSON from MongoDB Compass:
[{
"_id": {
"$oid": "63764d512bf0d70cbce32664"
},
"author": {
"$oid": "636fa1ce289c56d125ac8a4a"
},
"friend_id": {
"$oid": "636a88de3e45346191cf4257"
},
"request_at": {
"$date": {
"$numberLong": "1668697425541"
}
},
"__v": 0
},{
"_id": {
"$oid": "63764d622bf0d70cbce32673"
},
"author": {
"$oid": "636cf37d8a8b51a38932d3d8"
},
"friend_id": {
"$oid": "636a88de3e45346191cf4257"
},
"request_at": {
"$date": {
"$numberLong": "1668697442809"
}
},
"__v": 0
},{
"_id": {
"$oid": "637cc8e760709f87c46ad5a9"
},
"author": {
"$oid": "636a88de3e45346191cf4257"
},
"friend_id": {
"$oid": "636faabb1861c5b8773f751e"
},
"request_at": {
"$date": {
"$numberLong": "1669122279674"
}
},
"__v": 0
}]
Can you help me why it doesn't delete anything? Thanks!
I figured it out.
I just had to put a .exec() after the deleteMany query

How to reverse $unwind or re-assemble after $lookup?

I´ve been trying to reverse $unwind in nested array. Please, if you could help me it would be great. Thanks in advance.
Here are the details:
checklists collection, this collection has steps and each step has many areas, and I'd like to lookup to fill the area by id. I did it but I cannot reverse $unwind.
{
"steps": [{
"name": "paso1",
"description": "paso1",
"estimated_time": 50,
"active": true,
"areas": [{
"area_id": "60b6e728c44f0365c0d547d6"
}, {
"area_id": "60b6e7a2c44f0365c0d547d8"
}]
}, {
"name": "paso2",
"description": "o",
"estimated_time": 7,
"active": true,
"areas": [{
"area_id": "60b6e76ac44f0365c0d547d7"
}]
}, {
"name": "paso2",
"description": "l",
"estimated_time": 7,
"active": true,
"areas": [{
"area_id": "60b6e728c44f0365c0d547d6"
}]
}],
"name": "prueba",
"description": "prueba",
"type": "prueba",
"active": true,
"updated_at": {
"$date": "2021-06-02T23:56:02.232Z"
},
"created_at": {
"$date": "2021-06-01T22:44:57.114Z"
},
"__v": 0
}
area collection
{
"_id":"60b6e706c44f0365c0d547d5"
"name": "Development",
"short_name": "DEV",
"description": "Development area",
"updated_at": {
"$date": "2021-06-02T02:03:50.383Z"
},
"created_at": {
"$date": "2021-06-02T02:03:50.383Z"
},
"__v": 0,
"active": true
}
My aggregation
db.checklists.aggregate([
{
"$unwind": "$steps"
},
{
"$unwind": "$steps.areas"
},
{
"$lookup": {
"from": "areas",
"let": {
"area_id": {
"$toObjectId": "$steps.areas.area_id"
}
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$_id",
"$$area_id"
]
}
}
}
],
"as": "convertedItems"
}
},
{
"$group": {
"_id": "$steps.name",
"root": {
"$first": "$$ROOT"
},
"items": {
"$push": {
"$mergeObjects": [
"$steps.areas",
{
"$arrayElemAt": [
"$convertedItems",
0
]
}
]
}
},
}
},
{
"$addFields": {
"values": {
"$reduce": {
"input": "$items",
"initialValue": [],
"in": {
"$concatArrays": [
"$$value",
{
"$cond": [
{
"$in": [
"$$this.area_id",
"$$value.area_id"
]
},
[],
[
"$$this"
]
]
}
]
}
}
}
}
},
{
"$addFields": {
"root.steps.areas": "$values"
}
},
{
"$replaceRoot": {
"newRoot": "$root"
}
},
{
"$group": {
"_id": "$_id",
"root": {
"$first": "$$ROOT"
},
"steps": {
"$push": "$steps"
}
}
},
{
"$addFields": {
"root.steps": "$steps"
}
},
{
"$replaceRoot": {
"newRoot": "$root"
}
},
{
"$project": {
"convertedItems": 0
}
}
])
I don´t get to form this output:
{
"steps": [{
"name": "paso1",
"description": "paso1",
"estimated_time": 50,
"active": true,
"areas": [{
"_id": "60b6e728c44f0365c0d547d6",
"name":"Development",
..... //join or lookup
}, {
"_id": "60b6e7a2c44f0365c0d547d8",
"name":"Development",
..... //join or lookup
}]
}],
"name": "prueba",
"description": "prueba",
"type": "prueba",
"active": true,
"updated_at": {
"$date": "2021-06-02T23:56:02.232Z"
},
"created_at": {
"$date": "2021-06-01T22:44:57.114Z"
},
"__v": 0
}
Thank you very much!
$unwind deconstruct steps array
$lookup with areas collection pass area_id in let
$match to check is _id in area_ids after converting to string
$project to show required fields
$group by _id and reconstruct the steps array and pass your required fields
db.checklists.aggregate([
{ $unwind: "$steps" },
{
$lookup: {
from: "areas",
let: { area_id: "$steps.areas.area_id" },
pipeline: [
{
$match: {
$expr: { $in: [{ $toString: "$_id" }, "$$area_id"] }
}
},
{ $project: { name: 1 } }
],
as: "steps.areas"
}
},
{
$group: {
_id: "$_id",
steps: { $push: "$steps" },
name: { $first: "$name" },
description: { $first: "$description" },
type: { $first: "$type" },
active: { $first: "$active" },
updated_at: { $first: "$updated_at" },
created_at: { $first: "$created_at" },
__v: { $first: "$__v" }
}
}
])
Playground

MongoDB $lookup replace array of _id with array of objects without converting arrays to object and removing fields

I have an object like this:
{
"_id": {
"$oid": "5f0047f02fd3fc048aab9ee9"
},
"array": [
{
"_id": {
"$oid": "5f00dcc23e12b8721e4f3672"
},
"name": "NAME",
"sub_array": [
{
"sub_array2": [
{
"$oid": "5f00e367f7b8747beddc6d31"
},
{
"$oid": "5f00f26c1facd18c5158d1d3"
}
],
"_id": {
"$oid": "5f00de99a8802e767885e72b"
},
"week_day": 1
},
{
"sub_array2": [
{
"$oid": "5f00e367f7b8747beddc6d31"
}
],
"_id": {
"$oid": "5f00f2501facd18c5158d1d2"
},
"week_day": 3
}
]
},
{
"_id": {
"$oid": "5f00f2401facd18c5158d1d1"
},
"name": "NAME1",
"sub_array": []
}
]
}
I want to replace sub_array ids with objects from another collection but that results converting array and sub_array to objects and losing all of the data like week_day.
Lookup:
'$lookup': {
'from': 'sati',
'localField': 'array.sub_array.sub_array2',
'foreignField': '_id',
'as': 'array.sub_array.sub_array2'
}
Result:
{
"_id": {
"$oid": "5f0047f02fd3fc048aab9ee9"
},
"array": {
"sub_array": {
"sub_array2": [
{
"_id": {
"$oid": "5f00e367f7b8747beddc6d31"
},
"endTime": "2020-07-03T12:06:50+0000",
"startTime": "2020-07-03T12:05:50+0000",
"data1": {
"$oid": "5f005e63ab1cbf2374d5163f"
}
},
{
"_id": {
"$oid": "5f00e367f7b8747beddc6d31"
},
"endTime": "2020-07-03T12:06:50+0000",
"startTime": "2020-07-03T12:05:50+0000",
"data1": {
"$oid": "5f005e63ab1cbf2374d5163f"
}
},
{
"_id": {
"$oid": "5f00e367f7b8747beddc6d31"
},
"endTime": "2020-07-03T12:06:50+0000",
"startTime": "2020-07-03T12:05:50+0000",
"data1": {
"$oid": "5f005e63ab1cbf2374d5163f"
}
}
]
}
}
}
Is there a way to "replace" the individual ids without converting entire arrays to objects and removing other fields. I know mongoose can do that but I'm not permitted to use it. None of the other questions helped (example).
It will override entire object key:value with $lookup result. Instead, store the lookup result in the sati variable and add an extra stage like shown below.
$map allows use iterate over an array and transform each item.
db.collection.aggregate([
{
"$lookup": {
"from": "sati",
"localField": "array.sub_array.sub_array2",
"foreignField": "_id",
"as": "sati"
}
},
{
$project: {
array: {
$map: {
input: "$array",
as: "array",
in: {
_id: "$$array._id",
name: "$$array.name",
sub_array: {
$map: {
input: "$$array.sub_array",
as: "sub_array",
in: {
_id: "$$sub_array._id",
week_day: "$$sub_array.week_day",
sub_array2: {
$filter: {
input: "$sati",
as: "sati_item",
cond: {
$in: [
"$$sati_item._id",
"$$sub_array.sub_array2"
]
}
}
}
}
}
}
}
}
}
}
}
])
MongoPlayground | Altenative with $mergeObjects

How to find in specific date interval

I have problem in Mongodb to find wanted documents and fragment of list field. So I have following document:
{
"_id": "5ed38e5d2a6e74567c7a579c",
"id": "AAA",
"events": [
{
"dayTypeId": "5e71e1918ee9a326ebdf1611",
"startDate": {
"$date": "2020-06-01T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-04T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71e1918ee9a326ebdf1611",
"startDate": {
"$date": "2020-06-10T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-10T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71d8628ee9a326e7df160d",
"startDate": {
"$date": "2020-06-05T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-09T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71d8628ee9a326e7df160d",
"startDate": {
"$date": "2020-07-13T00:00:00.000Z"
},
"endDate": {
"$date": "2020-07-21T00:00:00.000Z"
},
"stared": false,
"userId": "XXXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
}
]
}
I want to get fragment of "events" list where either the startDate or the endDate is in the range of 02.06.2020-11.06.2020.
For example out of my sample data I want all but the last element to be returned.
You can use $filter to filter out any events that do not match your conditions:
db.collection.aggregate([
{
$match: {
$or: [
{
"events.startDate": {$gte: new Date("2020-06-02"), $lte: new Date("2020-06-11")}
},
{
"events.endDate": {$gte: new Date("2020-06-02"), $lte: new Date("2020-06-11")}
}
]
}
},
{
$project: {
events: {
$filter: {
input: "$events",
as: "event",
cond: {
$or: [
{
$and: [
{$gte: ["$$event.startDate", new Date("2020-06-02")]},
{$lte: ["$$event.startDate", new Date("2020-06-11")]},
]
},
{
$and: [
{$gte: ["$$event.endDate", new Date("2020-06-02")]},
{$lte: ["$$event.endDate", new Date("2020-06-11")]},
]
}
]
}
}
}
}
}
])

Aggregating array of values in elasticsearch

I need to aggregate an array as follows
Two document examples:
{
"_index": "log",
"_type": "travels",
"_id": "tnQsGy4lS0K6uT3Hwzzo-g",
"_score": 1,
"_source": {
"state": "saopaulo",
"date": "2014-10-30T17",
"traveler": "patrick",
"registry": "123123",
"cities": {
"saopaulo": 1,
"riodejaneiro": 2,
"total": 2
},
"reasons": [
"Entrega de encomenda"
],
"from": [
"CompraRapida"
]
}
},
{
"_index": "log",
"_type": "travels",
"_id": "tnQsGy4lS0K6uT3Hwzzo-g",
"_score": 1,
"_source": {
"state": "saopaulo",
"date": "2014-10-31T17",
"traveler": "patrick",
"registry": "123123",
"cities": {
"saopaulo": 1,
"curitiba": 1,
"total": 2
},
"reasons": [
"Entrega de encomenda"
],
"from": [
"CompraRapida"
]
}
},
I want to aggregate the cities array, to find out all the cities the traveler has gone to. I want something like this:
{
"traveler":{
"name":"patrick"
},
"cities":{
"saopaulo":2,
"riodejaneiro":2,
"curitiba":1,
"total":3
}
}
Where the total is the length of the cities array minus 1. I tried the terms aggregation and the sum, but couldn't output the desired output.
Changes in the document structure can be made, so if anything like that would help me, I'd be pleased to know.
in the document posted above "cities" is not a json array , it is a json object.
If changing the document structure is a possibility I would change cities in the document to be an array of object
example document:
cities : [
{
"name" :"saopaulo"
"visit_count" :"2",
},
{
"name" :"riodejaneiro"
"visit_count" :"1",
}
]
You would then need to set cities to be of type nested in the index mapping
"mappings": {
"<type_name>": {
"properties": {
"cities": {
"type": "nested",
"properties": {
"city": {
"type": "string"
},
"count": {
"type": "integer"
},
"value": {
"type": "long"
}
}
},
"date": {
"type": "date",
"format": "dateOptionalTime"
},
"registry": {
"type": "string"
},
"state": {
"type": "string"
},
"traveler": {
"type": "string"
}
}
}
}
After which you could use nested aggregation to get the city count per user.
The query would look something on these lines :
{
"query": {
"match": {
"traveler": "patrick"
}
},
"aggregations": {
"city_travelled": {
"nested": {
"path": "cities"
},
"aggs": {
"citycount": {
"cardinality": {
"field": "cities.city"
}
}
}
}
}
}

Resources