How to update values in string array in all documents? - MongoDB - mongodb

I have in my collection this structure:
{
_id: ObjectId('...'),
images: [
"images/key1",
"images/key2",
"images/key3",
"images/key4"
],
.... ,
....
}
So, I want to update all documents to:
{
_id: ObjectId('...'),
images: [
"key1",
"key2",
"key3",
"key4"
],
.... ,
....
}
Replacing in all values 'images/' with ''. Thanks 😁

you could done it with update aggregation like this
first match the doc and then in project use map and them split and choose last element
db.collection.update({},
[
{
$addFields: {
images: {
$map: {
input: "$images",
as: "i",
in: {
$last: {
$split: [
"$$i",
"images/"
]
}
}
}
}
}
}
],{multi:true})
https://mongoplayground.net/p/6fDBAlpKDBj
or use this
db.collection.update({},
[
{
$addFields: {
images: {
$map: {
input: "$images",
as: "i",
in: {
$arrayElemAt: [
{
$split: [
"$$i",
"images/"
]
},
1
]
}
}
}
}
}
],{multi:true})
replace $last with $arrayelementAt
https://mongoplayground.net/p/ecHMquZGazy

Related

Update or Insert object in array in MongoDB

I have the following collection
{
"_id" : ObjectId("57315ba4846dd82425ca2408"),
"myarray" : [
{
userId : "8bc32153-2bea-4dd5-8487-3b65e3aa0869",
Time:2022-09-20T04:44:46.000+00:00,
point : 5
},
{
userId : "5020db46-3b99-4c2d-8637-921d6abe8b26",
Time:2022-09-20T04:44:49.000+00:00
point : 2
},
]
}
These are my questions
I want to push into myarray if userId doesn’t exist, and if userid already exists then update time and point also I have to keep only 5 elements in the array if 6th element comes then I a have to sort the array based on Time and remove oldest time entry
what is the best way to do this in mongo using aggregation
FYI we are using Mongo 4.4
You can achieve this by using the aggregation pipeline update syntax, the strategy will be first to update the array (or insert a new element to it).
then if the size exceeds 5 we just filter it based on minimum value. like so:
const userObj = {point: 5, userId: "12345"};
db.collection.updateOne(
{ ...updateCondition },
[
{
$set: {
myarray: {
$cond: [
{
$in: [
userObj.userId,
{$ifNull: ["$myarray.userId", []]}
]
},
{
$map: {
input: "$myarray",
in: {
$cond: [
{
$eq: [
"$$this.userId",
userObj.userId
]
},
{
$mergeObjects: [
"$$this",
{
Time: "$$NOW", // i used "now" time but you can swap this to your input
point: userObj.point
}
]
},
"$$this"
]
}
}
},
{
$concatArrays: [
{ $ifNull: ["$myarray", []] },
[
{
userId: userObj.userId,
point: userObj.point,
Time: "$$NOW"
}
]
]
}
]
}
}
},
{
$set: {
myarray: {
$cond: [
{
$gt: [
{
$size: "$myarray"
},
5
]
},
{
$filter: {
input: "$myarray",
cond: {
$ne: [
"$$this.Time",
{
$min: "$myarray.Time"
}
]
}
}
},
"$myarray"
]
}
}
}
])
Mongo Playground

MongoDB Query: How can I aggregate an array of objects as a string

I have an array of objects where I want to make a string concatenating all of the same attributes from the array. Example:
{
_id: 123,
example_document: true,
people: [
{
name: "John",
age: 18
}, {
name: "Clint",
age: 20
}
]
}
And I wanna make a query where my result would be:
{
_id: 123,
example_document: true,
people: [
{
name: "John",
age: 18
}, {
name: "Clint",
age: 20
}
],
concat_names: "John, Clint"
}
I think aggregate is the path I should take, but I'm not being able to find a way of getting a string out of this, only concat array elements into another array. Anyone could help?
You can use $concat combined with $reduce to achieve this, like so:
db.collection.aggregate([
{
$addFields: {
concat_names: {
$reduce: {
input: "$people",
initialValue: "",
in: {
$concat: [
"$$value",
{
$cond: [
{
$eq: [
{
"$strLenCP": "$$value"
},
0
]
},
"",
", "
]
},
"$$this.name"
]
}
}
}
}
}
])
Mongo Playground
You can use aggregation operators $project, and $map:
db.collection.aggregate([
{
$project:
{
concat_names:
{
$map:
{
input: "$people",
as: "i",
in: "$$i.name"
}
}
}
}])

How to match string within embedded array or doc in MongoDB?

After searching for a whole day, I am doubting whether MongoDB can fulfill below requirement:
Q: How can I filter out documents that meet below conditions ?
In last array element of students_replies, there is a reply from a student whose name containing string 'ason'.
id_1: first_school, students_replies: [
{Date:20210101, replies: [
{name: jack, reply: 'I do not like this idea'},
{name: jason, reply: 'I would rather stay at home'},
{name: charles, reply: 'I have an plan to improve'},
]},
{Date:20210401, replies: [
...]},
{Date:20210801, replies: [
...]},
]
id_2: second_shool, students_replies: [..]
id_3: third_shool, students_replies: [...]
Mongoplayground
Use $slice and $regex
For your example this becomes:
db.collection.aggregate([
// project only the last reply
{
"$project": {
key: 1,
last_reply: {
"$slice": [
"$students_replies",
-1
]
}
}
},
// filter the documents
{
"$match": {
"last_reply.replies.name": {
"$regex": "ason"
}
}
}
])
https://mongoplayground.net/p/a9piw2WQ8n6
Since you need last array element of students_replies, use $arrayElemAt
db.collection.aggregate([
{
"$match": {
$expr: {
$regexMatch: {
input: {
$reduce: {
input: {
$arrayElemAt: [
"$students_replies.replies",
-1
]
},
initialValue: "",
in: {
$concat: [
"$$value",
"$$this.name",
","
]
}
}
},
regex: "ason"
}
}
}
},
{
"$project": {
"students_replies": 0
}
}
])
mongoplayground
another answer
db.collection.aggregate([
{
$match: {
$expr: {
$ne: [
{
$filter: {
input: {
$map: {
input: {
$arrayElemAt: [
"$students_replies.replies",
-1
]
},
as: "r",
in: "$$r.name"
}
},
as: "s",
cond: {
$regexMatch: {
input: "$$s",
regex: "ason"
}
}
}
},
[]
]
}
}
},
{
"$project": {
"students_replies": 0
}
}
])
mongoplayground

Splitting an alphanumeric string like "3a" or "32ab" in mongodb aggregation pipeline

I would like to split an alphanumeric string like 3a into "3" and "a". Please help if any one has an idea. I can't use the $split in mongodb aggregation.
I'm not sure that this is efficient, but this answer may give you a solution.
Since we can't use regex in $split,
First stage - divide the sentence into words and store in char[]
Flat the char[] using $unwind
Categorize all string into strings[] and all numbers into numbers[] using $facet. Here we use $match with regex
Then combined as what you need.
Assume this is your string.
{
char:"32ab"
}
The mongo script might be,
db.collection.aggregate([{$addFields: {
'char': {
$map: {
input: {
$range: [
0,
{
$strLenCP: '$char'
}
]
},
'in': {
$substrCP: [
'$char',
'$$this',
1
]
}
}
}
}}, {$unwind: {
path: '$char',
preserveNullAndEmptyArrays: false
}}, {$facet: {
strings: [
{
$match: {
'char': RegExp('^[A-Za-z]+$')
}
},
{
$group: {
_id: null,
arr: {
$push: '$char'
}
}
},
{
$project: {
combined: {
$reduce: {
input: '$arr',
initialValue: '',
'in': {
$concat: [
'$$value',
'$$this'
]
}
}
}
}
}
],
numbers: [
{
$match: {
'char': {
$not: RegExp('^[A-Za-z]+$')
}
}
},
{
$group: {
_id: null,
arr: {
$push: '$char'
}
}
},
{
$project: {
combined: {
$reduce: {
input: '$arr',
initialValue: '',
'in': {
$concat: [
'$$value',
'$$this'
]
}
}
}
}
}
]
}}, {$project: {
string: {
$arrayElemAt: [
{
$ifNull: [
'$strings.combined',
''
]
},
0
]
},
number: {
$toInt:{
$arrayElemAt: [
{
$ifNull: [
'$numbers.combined',
''
]
},
0
]
}
}
}}])
And the output is
{
string : "ab",
numbers: 32
}

how to project field in array with mongodb

my collection in mongo db like this:
{
name:"mehdi",
grades:
[
{
a:1,
b:[2,3,4],
c:3,
d:4,
e:5
},
{
a:11,
b:[22,33,44],
c:33,
d:44,
e:55
}
]
}
I want to get a result with project op to give me a specific field in an array like this:
{
name:"mehdi",
grades:
[
{
a:1,
b:2
},
{
a:11,
b:22
}
]
}
how can I do this?
You can use $map to select a,b fields using $type to determine whether it's an array or number:
db.collection.aggregate([
{
$project: {
grades: {
$map: {
input: "$grades",
in: {
a: { $cond: [ { $eq: [ { $type: "$$this.a" }, "array" ] }, { $arrayElemAt: [ "$$this.a", 0 ] }, "$$this.a" ] },
b: { $cond: [ { $eq: [ { $type: "$$this.b" }, "array" ] }, { $arrayElemAt: [ "$$this.b", 0 ] }, "$$this.b" ] },
}
}
}
}
}
])
Mongo Playground