I am having the following collection:
{
"price" : [
55800000,
62800000
],
"surface" : [
81.05,
97.4
],
}
I would want to calculate the price/m2. I have tried the following but got the following error: "$divide only supports numeric types, not array and array".
db.entries.aggregate(
[
{ $project: { url: 1, pricePerSquareMeter: { $divide: [ "$price", "$surfaces" ] } } }
]
)
Would you know how to solve this? Ultimately would want to have an array like this:
{
"price" : [
55800000,
62800000
],
"surface" : [
81.05,
97.4
],
"pricePerSquareMeter" : [
688463.91,
644763.86
]
}
Important: The price and surface should also be ordered so that the calculation is valid.
You can use below aggregation
db.collection.aggregate([
{ "$addFields": {
"pricePerSquareMeter": {
"$map": {
"input": { "$range": [0, { "$size": "$price" }] },
"in": {
"$divide": [
{ "$arrayElemAt": ["$price", "$$this"] },
{ "$arrayElemAt": ["$surface", "$$this"] }
]
}
}
}
}}
])
MongoPlayground
You can use below aggregation
db.entries.aggregate([
{ $addFields: {
pricePerSquareMeter: {
$map: {
input: '$price',
as: 'item',
in: {
$divide: [
"$$item",
{ $arrayElemAt: [
"$surface",
{ "$indexOfArray": ["$price", "$$item"] }
]}
]
}
}
},
}}])
Related
I have the following data:
{
_id: "1"
transitions: [
{
"_id" : "11"
"name" : "Tr1"
"checkLists" : [
{ _id: "111", name: "N1"},
{ _id: "112", name: "N2"}
]
}
]
}
I used the following code to get the name N2 by query of _id:112
db.collection.findOne({ 'transitions.checkLists._id: new ObjectId("112") } }}, { 'transitions.checkLists.$': 1 })
but the result returns back both of them:
{ _id: ObjectId("1"),
transitions:
[ { checkLists:
[ { name: 'N1', _id: ObjectId("111") },
{ name: 'N2', _id: ObjectId("112") } ] } ] }
I would like to find and get only the name N2 by query of _id:112
Expected Result:
{ _id: ObjectId("1"),
transitions:
[ { checkLists:
[ { name: 'N2', _id: ObjectId("112") } ] } ] }
You can do it via the aggregation framework as follow:
db.collection.aggregate([
{
$match: {
"transitions.checkLists._id": "111"
}
},
{
"$addFields": {
"transitions": {
"$map": {
"input": "$transitions",
"as": "t",
"in": {
"$mergeObjects": [
"$$t",
{
"checkLists": {
"$filter": {
"input": "$$t.checkLists",
"as": "c",
"cond": {
$eq: [
"$$c._id",
"111"
]
}
}
}
}
]
}
}
}
}
},
{
"$addFields": {
transitions: {
$filter: {
input: "$transitions",
as: "elem",
cond: {
"$ne": [
"$$elem.checkLists",
[]
]
}
}
}
}
}
])
Explained:
Match the transitions.checkLists._id element in first stage.
Map/mergeobjects with filtered checklists to filter only the needed object from the transitions.checkLists array.
Remove the transitions elements where no checkList exists.
( this need to be done to remove elements for same document where there is no matching _id's )
Playground
I'm trying to match documents without a substring in an array field, in an aggregation pipeline.
I believe I need to add a field and then do a $match on -1, but I'm stuck on $indexOfBytes to find substrings in an array field.
db.collectionName.aggregate([{$addFields:{indexOfA:{$indexOfBytes:['$arrayName.fieldName1.fieldName2','A']}}}])
I get the error:
MongoServerError: PlanExecutor error during aggregation :: caused by :: $indexOfBytes requires a string as the first argument, found: array
collection example:
[
{ arrayName: [ fieldName1: { fieldName2: 'A' } ] },
{ arrayName: [ fieldName1: { fieldName2: 'B' } ] },
{ arrayName: [ fieldName1: { fieldName2: 'C' } ] },
{ arrayName: [ ] }
]
desired result (:
[
{ arrayName: [ fieldName1: { fieldName2: 'B' } ] },
{ arrayName: [ fieldName1: { fieldName2: 'C' } ] },
{ arrayName: [ ] }
]
Maybe something like this:
db.collection.aggregate([
{
$addFields: {
arrayName: {
"$filter": {
"input": "$arrayName",
"as": "a",
"cond": {
$eq: [
{
$indexOfBytes: [
"$$a.fieldName1.fieldName2",
"A"
]
},
-1
]
}
}
}
}
},
{
$match: {
$expr: {
$ne: [
{
$size: "$arrayName"
},
0
]
}
}
}
])
Explained:
$filter arrayName elements not having A in fieldName2
$match only the non-empty arrayName arrays
playground
I have an object schema that looks like this:
{
"_id":"ObjectId(""30t00594537da2r7awe083va"")",
"balances":{
"intraday":[
[
1630939075734,
1899.09
],
[
1630939435939,
1899.32
],
[
1632306730756,
0
],
[
1632306759376,
0
],
[
1632272012916,
1372.22
]
]
}
}
I want to remove all arrays within "balances.intraday" array whose the second element is equal to 0.
so my desired array will looks like this:
{
"_id":"ObjectId(""30t00594537da2r7awe083va"")",
"balances":{
"intraday":[
[
1630939075734,
1899.09
],
[
1630939435939,
1899.32
],
[
1632272012916,
1372.22
]
]
}
}
I tried to use the $pull command but it only removes the index and not the whole array.
======================= Edit =======================
Thanks to Tom Slabbaert the solution is as follows :
db._get_collection().update_many(
{},
[
{
"$set": {
"balances.intraday": {
"$filter": {
"input": "$balances.intraday",
"cond": {
"$ne": [
{
"$arrayElemAt": [
"$$this",
1
]
},
0
]
}
}
}
}
}
])
You should use pipelined updates for this, like so:
db.collection.updateMany(
{},
[
{
$set: {
"balances.intraday": {
$filter: {
input: "$balances.intraday",
cond: {
$ne: [
{
$arrayElemAt: [
"$$this",
1
]
},
0
]
}
}
}
}
}
])
Mongo Playground
Upon the aggregate function, the output i have got is of the form :-
> [ { DescriptionArray:
[ 'Des1',
'Des2',
'Des3',
'Des4' ],
PicArray:
[ 'Pic1.jpeg',
'Pic2.jpeg',
'Pic3.jpeg',
'Pic4.jpeg' ] } ]
But, i want the output to be of the form :-
>[ { DescriptionArray:
[
['Des1'],
['Des2'],
['Des3'],
['Des4' ]
],PicArray:
[
['Pic1.jpeg'],
['Pic2.jpeg'],
['Pic3.jpeg'],
['Pic4.jpeg']
] } ]
The aggregate function of mine is as follows:-
>User.aggregate([
{
"$project": {
"_id": 0,
"DescriptionArray": {
"$reduce": {
"input": "$services.description",
"initialValue": [],
"in": {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
},
"PicArray": {
"$reduce": {
"input": "$services.badpic",
"initialValue": [],
"in": {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
}
}
}
])
The schema of my database is as follows:-
> var serviceSchema = new mongoose.Schema({
description:[String],
pic:[String]
})
Is there any way, i can get the output of my desired format?
I am using mongo version 3.4.3 and I have my documents stored in mongo like this -
{
"_id" : ObjectId("5ad5ab8aaf2808b739ba6ab2"),
"ResumeId" : "105839064",
"ResumeDetails" : {
"WorkProfile" : [
{
"Company" : "XXXXXXXXX",
"JobTitle" : "YYYYY",
"JobSkills" : {
"CommonSkills": [],
"OtherSkills": []
}
},
{
"Company" : "XXXXXXXX",
"JobTitle" : "YYYYYY",
"JobSkills" : {
"CommonSkills" : [
ObjectId("5ad5ab860b94c96c738e914a")
],
"OtherSkills" : [
ObjectId("5ad5ab860b94c96c738e9146")
]
}
},
{
"Company" : "XXXXXXX",
"JobTitle" : "YYYY"
}
],
"AdditionalSkills" : {
"CommonSkills" : [
ObjectId("5ad5ab860b94c96c738e9175"),
ObjectId("5ad5ab860b94c96c738e91f0"),
ObjectId("5ad5ab860b94c96c738e9241"),
ObjectId("5ad5ab860b94c96c738e919b")
],
"OtherSkills" : [
ObjectId("5ad5ab860b94c96c738e90e6"),
ObjectId("5ad5ab860b94c96c738e9142"),
ObjectId("5ad5ab860b94c96c738e9211"),
ObjectId("5ad5ab860b94c96c738e9293"),
ObjectId("5ad5ab860b94c96c738e92c8")
]
}
},
"DocId" : "51cb2f49-fcb9-46a0-9040-67e0f986be11"
}
I want to combine all the skills under WorkProfile and AdditionalSkills under 2 separate arrays. I tried the following query
db.ResumeParsedData.aggregate([
{$match: {'DocId': '51cb2f49-fcb9-46a0-9040-67e0f986be11'}},
{$project: {
'JobSkills': {'$concatArrays': [
'$ResumeDetails.WorkProfile.JobSkills.CommonSkills', '$ResumeDetails.WorkProfile.JobSkills.OtherSkills']
},
'AdditionalSkills': {'$setUnion': [
'$ResumeDetails.AdditionalSkills.CommonSkills', '$ResumeDetails.AdditionalSkills.OtherSkills']},
}
}]).pretty()
But I am getting the following output -
{
"_id" : ObjectId("5ad5ab8aaf2808b739ba6ab2"),
"JobSkills" : [
[
ObjectId("5ad5ab860b94c96c738e914a")
],
[
ObjectId("5ad5ab860b94c96c738e9146")
]
],
"AdditionalSkills" : [
ObjectId("5ad5ab860b94c96c738e90e6"),
ObjectId("5ad5ab860b94c96c738e9142"),
ObjectId("5ad5ab860b94c96c738e9175"),
ObjectId("5ad5ab860b94c96c738e919b"),
ObjectId("5ad5ab860b94c96c738e91f0"),
ObjectId("5ad5ab860b94c96c738e9211"),
ObjectId("5ad5ab860b94c96c738e9241"),
ObjectId("5ad5ab860b94c96c738e9293"),
ObjectId("5ad5ab860b94c96c738e92c8")
]
}
How can I fix the JobSkills array field. It currently coming as array of array fields.
I also tried to concatArrays twice as following:
db.ResumeParsedData.aggregate([
{$match: {'DocId': '51cb2f49-fcb9-46a0-9040-67e0f986be11'}},
{$project: {
'JobSkills': {'$concatArrays': { '$concatArrays': [
'$ResumeDetails.WorkProfile.JobSkills.CommonSkills',
'$ResumeDetails.WorkProfile.JobSkills.OtherSkills'
]}},
'AdditionalSkills': {'$setUnion': [
'$ResumeDetails.AdditionalSkills.CommonSkills',
'$ResumeDetails.AdditionalSkills.OtherSkills'
]},
} }
]).pretty()
You can use $reduce (which is available in 3.4) to flatten your array of arrays:
db.ResumeParsedData.aggregate([
{ $match: {"DocId": "51cb2f49-fcb9-46a0-9040-67e0f986be11"} },
{
$project: {
"JobSkills": {
$reduce: {
input: {
$concatArrays: ["$ResumeDetails.WorkProfile.JobSkills.CommonSkills", "$ResumeDetails.WorkProfile.JobSkills.OtherSkills"]
},
initialValue: [],
in: { $setUnion: [ "$$this", "$$value" ] }
}
},
"AdditionalSkills": {"$setUnion": [
"$ResumeDetails.AdditionalSkills.CommonSkills", "$ResumeDetails.AdditionalSkills.OtherSkills"]}
}
}
])
$setUnion guarantees that there will be no duplicates in final array