I want a query that will take the latest version out of each document, and check if some given string (applicationId) is in the list allowedApplications.
documents example:
{
"applicationId" : "y...",
"allowedApplications": ["x..."],
"name" : "some-name",
"version" : 3
}
{
"applicationId" : "y...",
"allowedApplications": ["x..."],
"name" : "some-name",
"version" : 2
}
{
"applicationId" : "x...",
"allowedApplications": ["y..."],
"name" : "some-other-name",
"version" : 1
}
So the MongoDB query is:
db.getCollection('..').aggregate(
[
{ "$match": { "allowedApplications": "x..." }},
{"$group": { "_id": "$name", "version": { "$max": "$version" }}}
]
)
And the query will output the name and version (I'll perhaps add the allowedApplications later).
I'm trying now to write this in Scala's mongodb driver.
I tried a bunch of stuff, for example:
collection
.aggregate(List(
`match`(equal("allowedApplications", "x..")),
group("$name", addToSet("version", addToSet("$max", "¢version")))
)
)
But couldn't get it to work.
Using Scala 2.13.1 and mongo-scala-driver 4.1.0.
Any help would be appreciated.
Found the answer:
collection
.aggregate(List(
`match`(equal("allowedApplications", "x...")),
group("$name", max("version", "$version"))
)
The order isn't quite the same, but just use the function in the accumulator field.
I have the following documents,
{
"_id" : ObjectId("5b85312981c1634f59751604"),
"date" : "0"
},
{
"_id" : ObjectId("5b85312981c1634f59751604"),
"date" : "20180330"
},
{
"_id" : ObjectId("5b85312981c1634f59751604"),
"date" : "20180402"
},
{
"_id" : ObjectId("5b85312981c1634f59751604"),
"date" : "20180323"
},
I tried to convert date to ISODate using $toDate in aggregation,
db.documents.aggregate( [ { "$addFields": { "received_date": { "$cond": [ {"$ne": ["$date", "0"] }, {"$toDate": "$date"}, new Date("1970-01-01") ] } } } ] )
the query executed fine, but when I
db.documents.find({})
to examine all the documents, nothing changed, I am wondering how to fix it. I am using MongoDB 4.0.6 on Linux Mint 19.1 X64.
As they mentioned in the comments, aggregate doesn't update documents in the database directly (just an output of them).
If you'd like to permanently add a new field to documents via aggregation (aka update the documents in the database), use the following .forEach/.updateOne method:
Your example:
db.documents
.aggregate([{"$addFields":{"received_date":{"$cond":[{"$ne":["$date","0"]}, {"$toDate": "$date"}, new Date("1970-01-01")]}}}])
.forEach(function (x){db.documents.updateOne({_id: x._id}, {$set: {"received_date": x.received_date}})})
Since _id's value is an ObjectID(), there may be a slight modification you need to do to {_id:x._id}. If there is, let me know and I'll update it!
Another example:
db.users.find().pretty()
{ "_id" : ObjectId("5acb81b53306361018814849"), "name" : "A", "age" : 1 }
{ "_id" : ObjectId("5acb81b5330636101881484a"), "name" : "B", "age" : 2 }
{ "_id" : ObjectId("5acb81b5330636101881484b"), "name" : "C", "age" : 3 }
db.users
.aggregate([{$addFields:{totalAge:{$sum:"$age"}}}])
.forEach(function (x){db.users.updateOne({name: x.name}, {$set: {totalAge: x.totalAge}})})
Being able to update collections via the aggregation pipeline seems to be quite valuable because of what you have the power to do with aggregation (e.g. what you did in your question, doing calculations based on other fields within the document, etc.). I'm newer to MongoDB so maybe updating collections via aggregation pipeline is "bad practice", but it works and it's been quite valuable for me. I wonder why it isn't more straight-forward to do?
Note: I came up with this method after discovering Nazo's now-deprecated .save() method. Shoutout to Nazo!
This is my data structure store in DB
{
"_id" : ObjectId("58a4e451c164f95c98e96235"),
"_class" : "com.contix.log.parser.log.Log",
"vin" : "6",
"esn" : "c",
"volt" : 11.32,
"internVolt" : 4.14,
"temp" : 39.49,
"timestamp" : NumberLong("1483375743285")
}
What I want to do is get latest 10 unique volt, internVolt, temp based on vin and esn String. Also needs latest timestamp. Then I'm trying to use mongo aggregate way to get right result.
db.log.aggregate({$sort:{timestamp:-1}},{$group:{_id : {esn:"$esn",vin:"$vin"},firstTimestamp:{$first:"$timestamp"},volts:{$addToSet:"$volt"}}},{$limit:5})
But this is my result looks like
{ "_id" : { "esn" : "b", "vin" : "2" }, "firstTimestamp" :
NumberLong("1485852368147"), "volts" : [ 11.95, 10.08, 10.77, 10.47,
11.41, 10.36, 10.96, 10.75, 10.39, 10.53, 10.1, 10.22, 11.16, 10.11, 11.87, 11.33, 11.82, 11.78, 10.25, 11.86, 10.5, 10.41, 11.3, 11.31, 11.97, 10.64, 11.57, 10.93, 10.02, 10.68, 10.9, 11.53, 10.46, 11.42, 11.73, 11.32, 10.19, 10.51, 11.35, 11.28, 10.65, 10.21, 11.18, 10.91, 11.43, 10.52, 11.34, 11.1, 10.99, 10.61, 10.28, 10.97, 10.3, 10.31, 11.81, 11.8, 10.42, 11.51, 10.72, 11.39, 10.69, 11.27, 11.11, 10.15, 10.78, 10.58, 11.49, 10.94, 11.64, 10.32, 11.63, 10.03, 10.81, 11.83, 10.82, 11.84, 10.79, 10.66, 11.21, 10.24, 11.75, 11.2 ] }
And other 4 similar stuff.
I don't know if there is any way that can trim $volts this kind data int group pipeline. The $limit or $skip operation seems use for whole documents.
My dream result should look like below.
{ "_id" : { "esn" : "b", "vin" : "2" }, "firstTimestamp" :
NumberLong("1485852368147"), "volts" : [ 10.81, 11.83, 10.82, 11.84, 10.79, 10.66, 11.21, 10.24, 11.75, 11.2 ], "innerVolts":[...], "temp":[...] }
If you need to trim the results, you can use projection and do something like this:
db.log.aggregate([
{$sort:{timestamp:-1}},
{$group:{
_id : {esn:"$esn",vin:"$vin"},
firstTimestamp:{$first:"$timestamp"},
volts:{$addToSet:"$volt"},
innerVolts:{$addToSet:"$innerVolt"},
temp:{$addToSet:"$temp"}
}},
{ $project: {
_id:1,
firstTimestamp:1,
volts: {$slice : ["$volts",10]},
innerVolts: {$slice : ["$innerVolts",10]},
temp: {$slice:["$temp",10]}
}}])
Hope my answer was helpful.
You can use the $slice modifier to trim the array to the lastest N items.
I would like to add new data into a child element of a field in mongodb using update query with $push and $each, But it directly insert the whole part of each operator. please help me to fix it. My query given below.
> db.Groups.insert({ "_id" : ObjectId("55b54aa4e2aa83f1f123a1a2"), "_creator" : ObjectId("55b2932cb57f47c0be6f071f"), "_messages" : ["hi"], "_inactive" : [ ], "_active" : [ Obje
> .Groups.update({ "_id" : ObjectId("55b54aa4e2aa83f1f123a1a2")},{$push: {_active : { $each: [ ObjectId("55b2932cb57f47c0be6f072f"), ObjectId("55b2932cb57f47c0be6f073f") ]}}});
Result after running these queries
{ "__v" : 39, "_active" : [ ObjectId("55b2932cb57f47c0be6f071f"), ObjectId("55b28b203a6b52e9b90e3cd4"), { "$each" : [ ObjectId("55b2932cb57f47c0be6f072f"), ObjectId("55b2932cb57f47c0be6f073f") ] } ], "_creator" : ObjectId("55b2932cb57f47c0be6f071f"), "_id" : ObjectId("55b54aa4e2aa83f1f123a1a2"), "_inactive" : [ ], "_messages" : [ "hi" ] }
Expected result
{ "__v" : 39, "_active" : [ ObjectId("55b2932cb57f47c0be6f071f"), ObjectId("55b28b203a6b52e9b90e3cd4"), ObjectId("55b2932cb57f47c0be6f072f"), ObjectId("55b2932cb57f47c0be6f073f") ], "_creator" : ObjectId("55b2932cb57f47c0be6f071f"), "_id" : ObjectId("55b54aa4e2aa83f1f123a1a2"), "_inactive" : [ ], "_messages" : [ "hi" ] }
The version of MongoDB here must be a very old version, and now confirmed as 2.0.4. This should even error in 2.2.x versions due to it interpretting the $each as a field and rejecting it due to the reserved $ in the field name.
Use at least MongoDB 2.4 if you intend to use $each, otherwise there is $pushAll, which is now considered deprecated. The only difference being between 2.4 and 2.6 is that earlier than 2.6 you need to combine this with the $sort modifer as well.
i met a problem about mongodb.
db.tt.find()
{ "_id" : ObjectId("513c971be4b1f9d71bc8c769"),
"name" : "a",
"comments" : [ { "name" : "2" }, { "name" : "3" } ]
}
above is a test document.
i want to pull comments.name = 2
i do
db.tt.update({'comments.name':'2'},{'$pull':{'comments.$.name':'2'}});
but the console print these message:
Cannot apply $pull/$pullAll modifier to non-array
my mongodb version is 2.0.6
who can help me? Thank you very much
Your $pull syntax is off, it should be:
db.tt.update({'comments.name': '2'}, {$pull: {comments: {name: '2'}}})