Mongodb How to pivot fields? - mongodb

I have collection in mongo db,
so I want the fields: Ip UtilizationReports.Start UtilizationReports.CpuReports.0.ProcName UtilizationReports.CpuReports.0.MaxUsage UtilizationReports.CpuReports.1.ProcName UtilizationReports.CpuReports.1.MaxUsage
for that I use this this code:
db.Agents.aggregate(
[
{
"$project" : {
"UtilizationReports.Start" : 0.0,
"UtilizationReports.Interval" : 0.0,
"UtilizationReports.LastLogin" : 0.0,
"Configuration" : 0.0,
"HealthReports" : 0.0,
"_id" : 0.0
}
},
{
"$unwind" : {
"path" : "$UtilizationReports.CpuReports"
}
},
{
"$match" : {
"UtilizationReports.CpuReports.0" : {
"$exists" : true
},
"UtilizationReports.0.CpuReports.0.ProcName" : {
"$exists" : true
}
}
}
],
{
"allowDiskUse" : false
}
);
and I get this data
but I want to pivot row "ProcName" to column and the value will be "MaxUsage"
I try this code but it doesn't work:
db.Agents.aggregate(
[
{
"$project" : {
"tmp" : {
"$arrayToObject" : {
"$zip" : {
"inputs" : [
"$items.key",
"$items.value"
]
}
}
}
}
},
{
"$group" : {
"_id" : {
"Ip" : "$Ip",
"StartReport" : "$UtilizationReports.Start"
},
"items" : {
"$addToSet" : {
"key" : "$UtilizationReports.CpuReports.ProcName",
"value" : "$UtilizationReports.CpuReports.MaxUsage"
}
}
}
},
{
"$addFields" : {
"tmp.Ip" : "$_id.Ip",
"tmp.StartReport" : "$_id.StartReport"
}
},
{
"$replaceRoot" : {
"newRoot" : "$tmp"
}
}
],
{
"allowDiskUse" : true
}
);
the error message:
ad projection specification, cannot include fields or add computed fields during an exclusion projection: { UtilizationReports.Interval: 0.0, UtilizationReports.LastLogin: 0.0, Configuration: 0.0, HealthReports: 0.0, _id: 0.0, tmp: { $arrayToObject: { $zip: { inputs: [ \"$items.key\", \"$items.value\" ]
The sample output:

$arrayToObject is New in version 3.6.
I use with mongoDB version 3.4

Related

mongoDB - how do i use projection and exclude a specific field with its value?

I have this array in a mongo document:
"labels" : [
{
"id" : "4b19c495-8c40-4c92-8c7d-ae9fb8defd20",
"labelCategory" : "Content",
"labelType" : "Content_label",
"code" : 5,
"labelName" : "HR Request Forms",
"trustValue" : 1.0,
"riskValue" : 0.0,
"sensitivity" : 0.2,
"concrete" : 0.8,
"threshold" : 2.0,
"abstracts" : [
"707babad-231f-82bb-014c-8506d3dc784e"
]
},
{
"id" : "707babad-231f-82bb-014c-8506d3dc784e",
"labelCategory" : "Content",
"labelType" : "Content_label",
"code" : 5,
"labelName" : "HR Information",
"trustValue" : 1.0,
"riskValue" : 0.0,
"sensitivity" : 0.2,
"concrete" : 0.2,
"threshold" : 2.0,
"abstracts" : []
},
{
"id" : "9cdce502-1dd9-4ef9-b78b-7f7c638490bf",
"labelCategory" : "Virtual",
"labelType" : "Virtual_label",
"code" : 1,
"labelName" : "Object Low Sensitive",
"trustValue" : 1.0,
"riskValue" : 0.0,
"sensitivity" : 0.0,
"concrete" : 0.0,
"threshold" : 0.0,
"abstracts" : []
}
],
For now all i have is this query:
db.getCollection('objects-89aafe20-780f-46ec-aaa0-a2d95bae542e').find(
{
objectCategory:"Content",
"labels":{
$elemMatch:{"labelCategory" : "Content", labelName:{$ne:"Other"}}
}
},
{objectName:1, _id:0, labels:{labelName:1}}
)
current output:
{
"labels" : [
{
"labelName" : "HR Request Forms"
},
{
"labelName" : "HR Information"
},
{
"labelName" : "Object Low Sensitive"
}
],
"objectName" : "hr-L1-4.xls"
}
I am trying to fetch only the "labelName" which related to an object which include "labelCategory" : "Content" (exclude the object that known as: "labelCategory" : "Virtual").
Any suggestions? Thanks.
$filter to iterate loop of labels and match both conditions, it will return filtered documents from labels array
$let to declare a labels variable and above $filter will be inside labels, $$labels in in refers declared variable, $$labels.labelName will return array of string
db.getCollection('objects-89aafe20-780f-46ec-aaa0-a2d95bae542e').find({
objectCategory: "Content",
labels: {
$elemMatch: {
labelCategory: "Content",
labelName: { $ne: "Other" }
}
}
},
{
_id: 0,
objectName: 1,
labels: {
$let: {
vars: {
labels: {
$filter: {
input: "$labels",
cond: {
$and: [
{ $eq: ["$$this.labelCategory", "Content"] },
{ $ne: ["$$this.labelName", "Other"] }
]
}
}
}
},
in: "$$labels.labelName"
}
}
})
Playground

MongoDB Match DATE between FAILS

I have a match like:
{
$and: [
{ $nor: [ { Meetings: { $exists: false } }, { Meetings: { $size: 0 } }, { Meetings: { $eq: null } } ] },
{ 'Meetings.MeetingDate': { $gte: ISODate("2020-12-23T00:00:01.000Z") } },
{ 'Meetings.MeetingDate': { $lte: ISODate("2020-12-23T23:59:59.999Z") } }
]
}
and on Mongo I have meetings from 2020-01-01 to 2020-12-31.
If I want to get only the 23rd ones, this match brings them but also from higer date like 25, 26, 30, etc...
What is the correct way to match date BETWEEN to get a specific date? (could be one day or a range...)
Here there is a Mongo Playground with a small example, but here works fine, I get all from the 29th.
I guess my problem is in my Aggregation. On the example I added MeetingDate on the root and in real life its a child array, maybe this is the problem.
db.getCollection("ClientProject").aggregate(
[
{
"$match" : {
"$and" : [
{
"$nor" : [
{
"Meetings" : {
"$exists" : false
}
},
{
"Meetings" : {
"$size" : 0.0
}
},
{
"Meetings" : {
"$eq" : null
}
}
]
},
{
"Meetings.MeetingDate" : {
"$gte" : ISODate("2020-12-30T00:00:01.000+0000")
}
},
{
"Meetings.MeetingDate" : {
"$lte" : ISODate("2020-12-31T23:59:59.999+0000")
}
}
]
}
},
{
"$project" : {
"ProjectName" : 1.0,
"ClientName" : 1.0,
"ClientResponsableName" : "$CreatedByName",
"ProjectType" : 1.0,
"ProjectSKU" : 1.0,
"Meetings" : 1.0
}
},
{
"$unwind" : {
"path" : "$Meetings",
"preserveNullAndEmptyArrays" : false
}
},
{
"$unwind" : {
"path" : "$Meetings.Invites",
"preserveNullAndEmptyArrays" : false
}
},
{
"$addFields" : {
"Meetings.Invites.MeetingDate" : "$Meetings.MeetingDate",
"Meetings.Invites.MeetingStartTime" : "$Meetings.StartTime",
"Meetings.Invites.MeetingEndTime" : "$Meetings.EndTime",
"Meetings.Invites.MeetingStatus" : "$Meetings.MeetingStatus",
"Meetings.Invites.ProjectId" : {
"$toString" : "$_id"
},
"Meetings.Invites.ProjectType" : "$ProjectType",
"Meetings.Invites.ProjectSKU" : "$ProjectSKU",
"Meetings.Invites.ProjectName" : "$ProjectName",
"Meetings.Invites.ClientId" : "$ClientId",
"Meetings.Invites.ClientName" : "$ClientName",
"Meetings.Invites.ClientResponsableName" : "$ClientResponsableName"
}
},
{
"$replaceRoot" : {
"newRoot" : "$Meetings.Invites"
}
},
{
"$sort" : {
"MeetingDate" : 1.0,
"MeetingStartTime" : 1.0,
"InviteStatus" : 1.0
}
}
],
{
"allowDiskUse" : false
}
);
cheers
The problem here is not related with the match on Date, it´s working. The problem is that each record has an array of meeting and each one has different dates, so even matching the correct date, the rest of the aggregation, Unwinds, etc... will use the the full record with all meetings, thats why I get with diferent dates.
Here I added an extra Match after $ReplaceRoot and worked... could use $filter too in some part of the aggregation..
cheers

Sort documents by value in the last element of an array that matches filter. Mongodb

I have a collection of evaluationGroups with the following documents structure:
{
"_id" : ObjectId("60073749694fd4d81e4d677d"),
"AlertSettingId" : ObjectId("5ffddaaa0b1d2c30b191599a"),
"CurrentStatus" : "success",
"Evaluations" : [
{
"EvaluatedAt" : ISODate("2021-01-19T19:47:18.850Z"),
"ReferenceValue" : 1.0,
"Status" : "success"
},
{
"EvaluatedAt" : ISODate("2021-01-19T19:52:16.423Z"),
"ReferenceValue" : 1.0,
"Status" : "triggered"
},
{
"EvaluatedAt" : ISODate("2021-01-19T21:47:16.400Z"),
"ReferenceValue" : 1.0,
"Status" : "success"
}
]
}
{
"_id" : ObjectId("60085ec60a264ce3829a6335"),
"AlertSettingId" : ObjectId("5ffddaaa0b1d2c30b191599a"),
"CurrentStatus" : "triggered",
"Evaluations" : [
{
"EvaluatedAt" : ISODate("2021-01-20T18:03:01.040Z"),
"ReferenceValue" : 1.0,
"Status" : "noDataFound"
},
{
"EvaluatedAt" : ISODate("2021-01-20T22:04:43.983Z"),
"ReferenceValue" : 1.0,
"Status" : "triggered"
},
{
"EvaluatedAt" : ISODate("2021-01-20T22:39:43.978Z"),
"ReferenceValue" : 1.0,
"Status" : "triggered"
},
]
}
{
"_id" : ObjectId("60099092f7386972de3e8a05"),
"AlertSettingId" : ObjectId("5ffddaaa0b1d2c30b191599a"),
"CurrentStatus" : "success",
"Evaluations" : [
{
"EvaluatedAt" : ISODate("2021-01-21T14:32:48.697Z"),
"ReferenceValue" : 1.0,
"Status" : "noDataFound"
},
{
"EvaluatedAt" : ISODate("2021-01-21T14:37:44.929Z"),
"ReferenceValue" : 1.0,
"Status" : "triggered"
},
{
"EvaluatedAt" : ISODate("2021-01-21T14:42:44.928Z"),
"ReferenceValue" : 1.0,
"Status" : "triggered"
},
{
"EvaluatedAt" : ISODate("2021-01-21T15:17:46.052Z"),
"ReferenceValue" : 1.0,
"Status" : "success"
}
]
}
What I need to do is to sort all evaluation groups by the latest evaluation inside Evaluations (using EvaluatedAt property as the sort), but that the evaluation has also status triggered.
So, to sum up, I have to sort the groups, by the latest triggered Evaluation date.
I was looking at the question: Mongodb: sort documents by value in the last element of an array
And I liked this response of how to sort by last item, (because latest evaluations are at the end of the array in my case):
db.collection.aggregate([
{
$addFields: {
lastSent: {
$let: {
vars: {
last: {
$arrayElemAt: [ "$messages", -1 ]
}
},
in: "$$last.commData.sent.dateTime"
}
}
}
},
{ $sort: { lastSent: 1 } },
{ $project: { lastSent: 0 } }
])
But I would need to also filter evaluations by status "triggered" before getting the latest one.
How can achieve this using MongoDB aggregate query?
You can use $filter operator,
$filter to filter Evaluations array on the base of Status
$max to get latest EvaluatedAt form filtered result
db.collection.aggregate([
{
$addFields: {
lastSent: {
$let: {
vars: {
filtered: {
$filter: {
input: "$Evaluations",
cond: { $eq: ["$$this.Status", "triggered"] }
}
}
},
in: { $max: "$$filtered.EvaluatedAt" }
}
}
}
},
{ $sort: { lastSent: 1 } },
{ $project: { lastSent: 0 } }
])
Playground

How to write mongo query

How I can get the total number of seats available for a particular movie (seats present in all the theatres for that movie) from the mongodb schema below.
I need to write a mongo query to get the results
{
"_id" : ObjectId("5d637b5ce27c7d60e5c42ae7"),
"name" : "Bangalore",
"movies" : [
{
"name" : "KGF",
"theatres" : [
{
"name" : "PVR",
"seats" : 45
},
{
"name" : "IMAX",
"seats" : 46
}
]
},
{
"name" : "Avengers",
"theatres" : [
{
"name" : "IMAX",
"seats" : 50
}
]
}
],
"_class" : "com.BMS_mongo.ZZ_BMS_mongo_demo.Entity.CityInfo"
}
I have written this code :
db.cities.aggregate( [
{ "$unwind" : "$movies" }, { "$unwind" : "$theatres" } ,
{ "$group" : { _id : "$movies.theatre`enter code here`s.seats" ,
total : { "$sum" : "$seats" } }
}
] )
My schema:
The following query can get us the expected output:
db.collection.aggregate([
{
$unwind:"$movies"
},
{
$unwind:"$movies.theatres"
},
{
$group:{
"_id":"$movies.name",
"movie":{
$first:"$movies.name"
},
"totalSeats":{
$sum:"$movies.theatres.seats"
}
}
},
{
$project:{
"_id":0
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d637b5ce27c7d60e5c42ae7"),
"name" : "Bangalore",
"movies" : [
{
"name" : "KGF",
"theatres" : [
{
"name" : "PVR",
"seats" : 45
},
{
"name" : "IMAX",
"seats" : 46
}
]
},
{
"name" : "Avengers",
"theatres" : [
{
"name" : "IMAX",
"seats" : 50
}
]
}
],
"_class" : "com.BMS_mongo.ZZ_BMS_mongo_demo.Entity.CityInfo"
}
Output:
{ "movie" : "Avengers", "totalSeats" : 50 }
{ "movie" : "KGF", "totalSeats" : 91 }
Query:
db.movie.aggregate([{ $unwind: { path: "$movies",} },
{ $unwind: { path: "$movies.theatres",} },
{ $group: { _id: "$movies.name", "moviename": { $first: "$movies.name" },
"totalSeats": { $sum: "$movies.theatres.seats" }} }])
I got the answer using this query ...
db.cities.aggregate( [
{ "$match" : { "name" : "Bangalore" } },
{ "$unwind" : "$movies" } ,
{ "$match" : {"movies.name" : "KGF"} },
{ "$unwind" : "$theatres" },
{ "$group" : { _id : "$movies.name", total : { "$sum" : "$movies.theatres.seats"
} } }
] )

How can i find document into document arrray in mongodb

I have one collection and that collection have array, and i wanna find that array ids which document ??
"_id" : ObjectId("5cde81d5f5622a42161c6065"),
"PhoneNumber" : "PhoneNumber",
"Nick" : "Nick",
"Token" : "Token1",
"MiniProfilePhoto" : "MiniPhoto",
"IsAndroid" : 1.0,
"ProfilePhotoId" : 0.0,
"ProfilePhotoKey" : 0.0,
"FriendMessages" : [
],
"Friends" : [
{
"FriendId" : ObjectId("5cde84a5f5622a42161c6068"),
"FriendState" : 2.0
},
{
"FriendId" : ObjectId("5cde740df5622a42161c6061"),
"FriendState" : 0.0
}
]
"_id" : ObjectId("5cde740df5622a42161c6061"),
"PhoneNumber" : "PhoneNumber1",
"Nick" : "Nick2",
"Token" : "Token4",
"MiniProfilePhoto" : "MiniPhoto5",
"IsAndroid" : 1.0,
"ProfilePhotoId" : 0.0,
"ProfilePhotoKey" : 0.0,
"FriendMessages" : [
],
"Friends" : [
{
"FriendId" : ObjectId("5cde81d5f5622a42161c6065"),
"FriendState" : 1.0
}
]
"_id" : ObjectId("5cde84a5f5622a42161c6068"),
"PhoneNumber" : "PhoneNumber",
"Nick" : "Nick",
"Token" : "Token",
"MiniProfilePhoto" : "MiniPhoto",
"IsAndroid" : 0.0,
"ProfilePhotoId" : 0.0,
"ProfilePhotoKey" : 0.0,
"FriendMessages" : [
],
"Friends" : [
{
"FriendId" : ObjectId("5cde81d5f5622a42161c6065"),
"FriendState" : 2.0
}
]
...
//that is my collection example, ObjectId("5cde81d5f5622a42161c6065")' s two friends, and that ids "FriendId" : ObjectId("5cde84a5f5622a42161c6068") and ObjectId("5cde740df5622a42161c6061") and i wanna find ObjectId("5cde84a5f5622a42161c6068") and ObjectId("5cde740df5622a42161c6061")'s tokens, how can i find my friends tokens? what is that aggregate?
Here is your aggregation Query,
let query = [
{
$match: {
_id: ObjectId("5cde81d5f5622a42161c6065")
}
},
{
$project: {
Friends: 1,
Token: 1
}
},
{
$unwind: "$Friends"
},
{
$lookup: {
from: "tets",
localField: "Friends.FriendId",
foreignField: "_id",
as: "fdata"
}
},
{
$unwind: { path: "$fdata", preserveNullAndEmptyArrays: true }
},
{
$group: {
_id: "$_id",
fdata: { $push: { Token: "$fdata.Token", _id: "$fdata._id" } }
}
}
]
db.collection.aggregate(query)
Output:
{
"_id" : ObjectId("5cde81d5f5622a42161c6065"),
"fdata" : [
{
"Token" : "Token",
"_id" : ObjectId("5cde84a5f5622a42161c6068")
},
{
"Token" : "Token4",
"_id" : ObjectId("5cde740df5622a42161c6061")
}
]
}