MongoDB querying to with changing values for key - mongodb

Im trying to get back into Mongodb and Ive come across something that I cant figure out.
I have this data structure
> db.ratings.find().pretty()
{
"_id" : ObjectId("55881e43424cbb1817137b33"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "like",
"time" : 1434984003156,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
{
"_id" : ObjectId("55893be1e6a796c0198e65d3"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "dislike",
"time" : 1435057121808,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
{
"_id" : ObjectId("55893c21e6a796c0198e65d4"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "null",
"time" : 1435057185089,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
What I want to be able to do is count the documents that have either a like or dislike leaving the "null" out of the count. So I should have a count of 2. I tried to go about it like this whereby I set the query to both fields:
db.ratings.find({e_id: ObjectId("5565e106cd7a763b2732ad7c")}, {type: "like", type: "dislike"})
But this just prints out all three documents. Is there any reason?
If its glaringly obvious im sorry pulling out my hair at the moment.

Use the following db.collection.count() method which returns the count of documents that would match a find() query:
db.ratings.count({
"e_id": ObjectId("5565e106cd7a763b2732ad7c"),
type: {
"$in": ["like", "dislike"]
}
})
The db.collection.count() method is equivalent to the db.collection.find(query).count() construct. Your query selection criteria above can be interpreted as:
Get me the count of all documents which have the e_id field values as ObjectId("5565e106cd7a763b2732ad7c") AND the type field which has either value "like" or "dislike", as depicted by the $in operator that selects the documents where the value of a field equals any value in the specified array.

db.ratings.find({e_id: ObjectId("5565e106cd7a763b2732ad7c")},
{type: "like", type: "dislike"})
But this just prints out all three
documents. Is there any reason? If its glaringly obvious im sorry
pulling out my hair at the moment.
The second argument here is the projection used by the find method . It specifies fields that should be included -- regardless of their value. Normally, you specify a boolean value of 1 or true to include the field. Obviously, MongoDB accepts other values as true.
If you only need to count documents, you should issue a count command:
> db.runCommand({count: 'collection',
query: { "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}
})
{ "n" : 2, "ok" : 1 }
Please note the Mongo Shell provides the count helper for that:
> db.collection.find({ "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}).count()
2
That being said, to quote the documentation, using the count command "can result in an inaccurate count if orphaned documents exist or if a chunk migration is in progress." To avoid that, you might prefer using the aggregation framework:
> db.collection.aggregate([
{ $match: { "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}},
{ $group: { _id: null, n: { $sum: 1 }}}
])
{ "_id" : null, "n" : 2 }

This query should solve your problem
db.ratings.find({$or : [{"type": "like"}, {"type": "dislike"}]}).count()

Related

find() return the latest value only on MongoDB

I have this collection in MongoDB that contains the following entries. I'm using Robo3T to run the query.
{
"_id" : ObjectId("xxx1"),
"Evaluation Date" : "2021-09-09",
"Results" : [
{
"Name" : "ABCD",
"Version" : "3.2.x"
}
]
"_id" : ObjectId("xxx2"),
"Evaluation Date" : "2022-09-09",
"Results" : [
{
"Name" : "ABxD",
"Version" : "5.2.x"
}
]
}
This document contains multiple entries of similar format. Now, I need to extract the latest value for "Version".
Expected output:
5.2.x
Measures I've taken so far:
(1) I've only tried findOne() and while I was able to extract the value of "Version": db.getCollection('TestCollectionName').findOne().Results[0].Version
...only the oldest entry was returned.
3.2.x
(2) Using the find().sort().limit() like below, returns the entire document for the latest entry and not just the data value that I wanted; db.getCollection('TestCollectionName').find({}).sort({"Results.Version":-1}).limit(1)
Results below:
"_id" : ObjectId("xxx2"),
"Evaluation Date" : "2022-09-09",
"Results" : [
{
"Name" : "ABxD",
"Version" : "5.2.x"
}
]
(3) I've tried to use sort() and limit() alongside findOne() but I've read that findOne is maybe deprecated and also not compatible with sort. And thus, resulting to an error.
(4) Finally, if I try to use sort and limit on find like this: db.getCollection('LD_exit_Evaluation_Result_MFC525').find({"Results.New"}).sort({_id:-1}).limit(1) I would get an unexpected token error.
What would be a good measure for this?
Did I simply mistake to/remove a bracket or need to reorder the syntax?
Thanks in advance.
I'm not sure if I understood well, but maybe this could be what are you looking for:
db.collection.aggregate([
{
"$project": {
lastResult: {
"$last": "$Results"
},
},
},
{
"$project": {
version: "$lastResult.Version",
_id: 0
}
}
])
It uses aggregate with some operators: the first $project calculate a new field called lastResult with the last element of each array using $last operator. The second $project is just to clean the output. If you need the _id reference, just remove _id: 0 or change its value to 1.
You can check how it works here: https://mongoplayground.net/p/jwqulFtCh6b
Hope I helped

Why do I get this result from a multiple criteria query?

On mongo, I issue the following query:
db.usertest.find({ "events.event":"event0", "events.event":"event1", "events.event":"eventX" })
As per the docs here http://docs.mongodb.org/manual/tutorial/query-documents/#id4 I would expect this to only match documents that had all these three elements in an array.
However, it matches this doc:
{ "_id" : "userbruce", "events" : [ { "event" : "eventX" } ] }
Why?
The docs say that this format matches documents that "contain elements that in some combination satisfy the query conditions" What is matching event0 or event1?
EDIT: Is it getting confused because I put in the same field each time?
For AND operation in with this data, please try below query:
db.usertest.find({$and : [{ "events.event":"event0"}, {"events.event":"event1"}, {"events.event":"eventX" }]})
And yes, the confusion is because you given same field each time. IF you try something like below document:
{
"_id" : "userbruce",
"events" : [
{
"eventA" : "eventX"
},
{
"eventB" : "event0"
},
{
"eventC" : "event1"
}
]
}
then, your query would not have given any result. So, your query stands correct, but the data is not appropriate for that query.

MongoDB - Get highest value of child

I'm trying to get the highest value of a child value. If I have two documents like this
{
"_id" : ObjectId("5585b8359557d21f44e1d857"),
"test" : {
"number" : 1,
"number2" : 1
}
}
{
"_id" : ObjectId("5585b8569557d21f44e1d858"),
"test" : {
"number" : 2,
"number2" : 1
}
}
How would I get the highest value of key "number"?
Using dot notation:
db.testSOF.find().sort({'test.number': -1}).limit(1)
To get the highest value of the key "number" you could use two approaches here. You could use the aggregation framework where the pipeline would look like this
db.collection.aggregate([
{
"$group": {
"_id": 0,
"max_number": {
"$max": "$test.number"
}
}
}
])
Result:
/* 0 */
{
"result" : [
{
"_id" : 0,
"max_number" : 2
}
],
"ok" : 1
}
or you could use the find() cursor as follows
db.collection.find().sort({"test.number": -1}).limit(1)
max() does not work the way you would expect it to in SQL for Mongo.
This is perhaps going to change in future versions but as of now,
max,min are to be used with indexed keys primarily internally for
sharding.
see http://www.mongodb.org/display/DOCS/min+and+max+Query+Specifiers
Unfortunately for now the only way to get the max value is to sort the
collection desc on that value and take the first.
db.collection.find("_id" => x).sort({"test.number" => -1}).limit(1).first()
quoted from: Getting the highest value of a column in MongoDB

Extract two sub array values in mongodb by $elemMatch

Aggregate, $unwind and $group is not my solution as they make query very slow, there for I am looking to get my record by db.collection.find() method.
The problem is that I need more then one value from sub array. For example from the following example I want to get the "type" : "exam" and "type" : "quiz" elements.
{
"_id" : 22,
"scores" : [
{
"type" : "exam",
"score" : 75.04996547553947
},
{
"type" : "quiz",
"score" : 10.23046475899236
},
{
"type" : "homework",
"score" : 96.72520512117761
},
{
"type" : "homework",
"score" : 6.488940333376703
}
]
}
I am looking something like
db.students.find(
// Search criteria
{ '_id': 22 },
// Projection
{ _id: 1, scores: { $elemMatch: { type: 'exam', type: 'quiz' } }}
)
The result should be like
{ "_id": 22, "scores" : [ { "type" : "exam", "type" : "quiz" } ] }
But this over ride the type: 'exam' and returns only type: 'quiz'. Have anybody any idea how to do this with db.find()?
This is not possible directly using find and elemMatch because of following limitation of elemMatch and mongo array fields.
The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition. ref. from $elemMacth
and mongo array field limitations as below
Only one positional $ operator may appear in the projection document.
The query document should only contain a single condition on the array field being projected. Multiple conditions may override each other internally and lead to undefined behavior. ref from mongo array field limitations
So either you tried following this to find out only exam or quiz
db.collectionName.find({"_id":22,"scores":{"$elemMatch":{"type":"exam"}}},{"scores.$.type":1}).pretty()
is shows only exam scores array.
Otherwise you should go through aggregation

Yet another MongoDB findAndModify

Please consider the following document, a part of the Runtime collection:
{
"entity_id" : 10,
"features" : [
{
"10" : "Test System 2"
},
{
"20" : "System 2 Description"
},
{
"180" : ISODate("2013-12-25T18:19:40.589Z")
},
{
"190" : ISODate("2013-12-25T18:19:40.589Z")
}
],
"_id" : ObjectId("52bb21bc8a2ebdc01c000001")
}
My goal is to update the value of the element of the "features" array having the key "20".
Here are the things I've tried (in mongo shell):
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features.$.20":"Updated Description"}}} );
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features['20']":"Updated Description"}}} );
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features[1]":"Updated Description"}}} );
In all instances the shell prints
null
and nothing happens to the data. So, the main question is, of course, what is wrong with my code snippets. Also, how that "null" is supposed to get interpreted? And is there such a thing as mongo shell's log where one could find any clues? Many thanks for your help!
When using the $ positional operator in an update, your query needs to include a term that matches the element of the array you're updating:
db.Runtime.findAndModify({
query: {_id: ObjectId("52bb21bc8a2ebdc01c000001"),
'features.20': {$exists: true}},
update: {$set: {"features.$.20":"Updated Description"}}
})
Note that you also need to call ObjectId on your _id string to turn it into an actual ObjectId or it won't match the doc.