Genric Object based query in mongodb - spring-data

I'm using Spring Data MongoDB and, say want to query the following document:
{
"id":3,
"updatedOn" : ISODate("2018-11-22T10:58:48.536Z"),
"totalMaxScore" : 50,
"maxAttempts" : 4,
"sections" : [
{
"sectionName" : "coding",
"maxScore" : 30,
"concepts" : [
"css box model"
],
"skills" : [
"is aware of css syntax"
],
"difficultyLevel" : "easy",
"weightage" : 48
}
]
From Mongo Client I'm able to do: db.quiz.find({'sections.skills': 'is aware of css syntax'}).pretty()
But I want to search programatically documents based on skills provided at runtime. I understand I need to use #Query but need help on the generic query to write.

Sorry for the late answer.
#Query(value = "{ 'sections':{$elemMatch:{'skills: {$elemMatch: {$eq: ?0 }}}}})"
List<Challenge> findChallengesBySkill(String skill);

Related

How to reduce execution time in this mongo db find query?

document sample data followed like this,
{
"_id" : ObjectId("62317ae9d007af22f984c0b5"),
"productCategoryName" : "Product category 1",
"productCategoryDescription" : "Description about product category 1",
"productCategoryIcon" : "abcd.svg",
"status" : true,
"productCategoryUnits" : [
{
"unitId" : ObjectId("61fa5c1273a4aae8d89e13c9"),
"unitName" : "kilogram",
"unitSymbol" : "kg",
"_id" : ObjectId("622715a33c8239255df084e4")
}
],
"productCategorySizes" : [
{
"unitId" : ObjectId("61fa5c1273a4aae8d89e13c9"),
"unitName" : "kilogram",
"unitSize" : 10,
"unitSymbol" : "kg",
"_id" : ObjectId("622715a33c8239255df084e3")
}
],
"attributes" : [
{
"attributeId" : ObjectId("62136ed38a35a8b4e195ccf4"),
"attributeName" : "Country of Origin",
"attributeOptions" : [],
"isRequired" : true,
"_id" : ObjectId("622715ba3c8239255df084f8")
}
]
}
This collection has been indexed in "_id". without sub-documents execution time is reduced but all document fields are required.
db.getCollection('product_categories').find({})
This collection contains 30000 records and this query takes more than 30 seconds to execute. so how to solve this issue. Anybody ask me a better solution. Thanks.
Indexing and compound indexing will make it use cache instead of scanning document every time you query it. 30.000 documents is nothing to MongoDB, it can handle millions in a second. If these fields are populated in the process that's another heavy operation for the query.
See if your schema is efficiently structured or you're throttling your connection to the server. Other thing to consider is to project only the fields that you require, using aggregation pipeline.
Although the question is not very clear you can follow this article for some best practices.

how to use update query in mongoDb?

I have few documents in user Collection like below .I need to update ancestors field alone,Need to add few more values.
db.users.find()
{
"_id" : ObjectId("5d9fd81f3d598088d2ea5dcc"),
"DOB" : ISODate("1979-05-23T00:00:00Z"),
"userImage" : "sathish_1589780950636.jpeg",
"createdDateTime" : ISODate("2016-02-01T09:43:27Z"),
"modifiedDateTime" : ISODate("2017-04-26T15:57:09Z"),
"status" : "active",
"ancestors" : [
ObjectId("5d9fd81b3d598088d2ea5dc7")
],
"parent" : ObjectId("5d9fd81b3d598088d2ea5dc7")
}
When i tried the below query.
db.users.update({"_id" : ObjectId("5d9fd81f3d598088d2ea5dcc")},{$set:{"ancestors" : [
ObjectId("5f45f9491ff4bd74ec754e3a"),
ObjectId("5d9fd8203d598088d2ea5dcd"),
ObjectId("5d9fd8723d598088d2ea5e43")
]}})
It just replace the old one and completely adding the new one.
I need the result to be like this .old data should also remain and new one should be added.
"ancestors" : [
ObjectId("5f45f9491ff4bd74ec754e3a"),
ObjectId("5d9fd8203d598088d2ea5dcd"),
ObjectId("5d9fd81b3d598088d2ea5dc7"),
ObjectId("5d9fd8723d598088d2ea5e43")
]
This update query should be done in all documents in that collection. the above mentioned 3 values to be added in all documents, instead of find and update, I should be doing bulk updated
I think you can run the following:
db.users.updateOne({"_id" : ObjectId("5d9fd81f3d598088d2ea5dcc")},{$addToSet:{"ancestors" :{ $each: [
ObjectId("5f45f9491ff4bd74ec754e3a"),
ObjectId("5d9fd8203d598088d2ea5dcd"),
ObjectId("5d9fd8723d598088d2ea5e43")
]}}})
ref: https://docs.mongodb.com/manual/reference/operator/update/each/
You can use mongodb method $push
db.users.update({"_id" : ObjectId("5d9fd81f3d598088d2ea5dcc")},
{ $push: {ancestors:ObjectId("5f45f9491ff4bd74ec754e3a") } })
[check doc][1]
[1]: https://docs.mongodb.com/manual/reference/operator/update/push/

Error in mongodb query to get movie based on id

> db.movmodels.findOne()
{
"_id" : ObjectId("55320b0e0e9e0d9d0540593c"),
"username" : "punk",
"favMovies" : [
{
"alternate_ids" : {
"imdb" : "0137523"
},
"abridged_cast" : [
{
"characters" : [
"Tyler"
],
"id" : "162652627",
"name" : "Brad Pitt"
},
{
"characters" : [
"Narrator"
],
"id" : "162660884",
"name" : "Edward Norton"
},
{
"characters" : [
"Robert"
],
"id" : "162676383",
"name" : "Meat Loaf"
},
{
"characters" : [
"Angel Face"
],
"id" : "162653925",
"name" : "Jared Leto"
},
{
"characters" : [
"Boss"
],
"id" : "770706064",
"name" : "Zach Grenier"
}
],
"synopsis" : "",
"ratings" : {
"audience_score" : 96,
"audience_rating" : "Upright",
"critics_score" : 80,
"critics_rating" : "Certified Fresh"
},
"release_dates" : {
"dvd" : "2000-06-06",
"theater" : "1999-10-15"
},
"critics_consensus" : "",
"runtime" : 139,
"mpaa_rating" : "R",
"year" : 1999,
"title" : "Fight Club",
**"id" : "13153"**
}
],
"__v" : 0
}
This is my data in mongodb.
As I am new to mongodb I wanted to know query to get movie with a particular id.
The query that I tried is. I need to get the movie based on id so that I can remove it from my database
db.movmodels.findOne({username:"punk"},{favMovies:{id:13153}})
but this gives me error.
2015-04-18T05:41:26.221-0400 E QUERY Error: error: {
"$err" : "Can't canonicalize query: BadValue ported projection option: favMovies: { id: 13153.0 }",
"code" : 17287
}
at Error (<anonymous>)
at DBQuery.next (src/mongo/shell/query.js:259:15)
at DBCollection.findOne (src/mongo/shell/collection.js:188:22)
at (shell):1:14 at src/mongo/shell/query.js:259
There are several problems with your query:
The second parameter to find() is a projection, not part of the query. What you want is to supply one document for the query that has two properties: {"username" : "punk", favMovies : { ... } }
However, you also don't want to compare the entire sub-document favMovies, but you only want to match on one of its properties, the id, which requires to 'reach into the object' using the dot operator: {username:"punk", "favMovies.id" : 13153}.
However, that will probably not work yet, because 13153 is not the same as "13153", the latter being a string while the former is a number in JSON.
db.movmodels.findOne({username:"punk", "favMovies.id" : "13153"})
Keep in mind, however, that this will find the entire document for the user named "punk". I'm not sure what exactly your data structure should look like, but it appears you'll have to $pull the movie from the user. In general, I'd say you're embedding too much data into the user, but that's hard to tell without knowing the exact use case.
Here you go:
If you just wanted to get first user who has this fav movie:
db.movmodels.findOne({"favMovies.id": 13153});
And, if you want to know if that user has that movie as favorite.
db.movmodels.findOne({"favMovies.id": 13153, username:"punk"});
Second argument in the findOne is used to only return particular field.
You can use also $elemMatch projection operator (not to be confused with the $elemMatch query operator)
db.movmodels.find({username:"punk"},{favMovies:{$elemMatch:{id:"13153"}}});
`
If you want to find a movie that has another movie (with id 13153) in 'favMovies' array, then write the query as below:
db.movmodels.findOne({username:"punk",'favMovies.id':13153})
And if you want to find a movie with _id 55320b0e0e9e0d9d0540593cwrite the following query:
db.movmodels.findOne({username:"punk",'_id':ObjectId("55320b0e0e9e0d9d0540593c")})

How to query an array in an array of objects in mongodb?

I am pretty new to mongodb, and I am not able to query in my mongo collection.
Structure :
"chapterId":1,
"videos" : [
{
"videoId" : "1",
"videoName" : "about",
"duration" : "12:36",
"tags":["business", "design"]
},
{
"videoId" : "2",
"videoName" : "course",
"duration" : "04:00",
"tags":["technology", "design"]
}
]
I need to select all videos with the tag "business" in chapterId 1.
Can this be done without changing the structure of my collection ?
You should use aggregation so below query will help you
db.collectionName.aggregate(
{"$unwind":"$videos"},
{"$match":{"chapterId":1,"videos.tags":"business"}}
)

MongoDB query help: $elemMatch in nested objects

> db.test.insert({"a" : { "b" : { "c" : { "d1" : [ "e1" ],
"d2" : [ "e2" ],
"d3" : [ "e3", "e4" ],
"d4" : [ "e5", "e6" ] } } } })
> db.test.find({'a.b.c' : {$exists : true}})
{ "_id" : ObjectId("4daf2ccd697ebaacb10976ec"), "a" : { "b" : { "c" : { "d1" : [ "e1" ], "d2" : [ "e2" ], "d3" : [ "e3", "e4" ], "d4" : [ "e5", "e6" ] } } } }
But none of these work:
> db.test.find({'a.b': "c"})
> db.test.find({'a.b': {$elemMatch : {"c" : {$exists: true}}}})
> db.test.find({'a.b': {$elemMatch : {$elemMatch : {$all : ["e1"] }}}})
Suppose I don't know what the values of c and d1...d4 are. Is there a generic way to search the nested-objects' structure for particular values?
I thought that was what $elemMatch was for.
Thank you.
I thought that was what $elemMatch was for...
From the docs: Using the $elemMatch query operator, you can match an entire document within an array.
This does not sounds like what you're looking for.
Is there a generic way to search the nested-objects' structure for particular values?
It sounds like you want to search "everything in object 'c' for an instance of 'e1'".
MongoDB supports two related features, but the features not quite what you're looking for.
Reach into objects, dot notation: db.test.find({'a.b.c.d1' : 'e1'})
Read through arrays: `db.test.find({'a.b.c.d4' : 'e5'})
It sounds like you're looking for the ability to do both at the same time. You want to "reach into objects" and "read through arrays" in the same query.
Unfortunately, I do not know of such a feature. You may want to file a feature request for this.
I believe the query you're looking for is
db.test.find({ 'a.b.c': { '$exists': true } });
To your credit, you were very close!