MongoDB find query with $ref and $id - mongodb

I'm struggling with a mongodb query.
Given this query 1:
db.procedures.find({'procedure.name':'nameOfMyProcedure'})
and this query 2:
db.procedure_executions.find({'foo.bar':'whatever'})
Query 1 returns a lot of procedure objects that look like this in shortened version:
{
"_id": ObjectId("5564df8d30041530fb68e1eb"),
"_class": "eu.whatever.model.db.impl.DbProcedureExecutionImpl",
"procedure": {
"_class": "eu.whatever.common.model.impl.ProcedureImpl",
"className": "eu.whatever",
"name": "nameOfMyProcedure",
"kind": "METHOD",
"arguments": []
},
"caller": {
"$ref": "procedure_executions",
"$id": ObjectId("5564df8d30041530fb68e1e8")
}
}
The resulting objects of query 2 are referenced as "caller" in query 1.
How can I filter procedures (query 1) by the referenced caller and its attributes (query 2) in a single nested query?
I came across $in. Is it possible to add a query to another collection (procedure_executions) within $in?

"I'm new here myself", but try:
db.procedures.find(
{'procedure.name':'nameOfMyProcedure'},
{'caller.$ref': 'procedure_executions'})
From $and:
NOTE:
MongoDB provides an implicit AND operation when specifying a comma separated list of expressions. Using an explicit AND with the $and operator is necessary when the same field or operator has to be specified in multiple expressions.

Related

Mongo queries to search all the collections of a database (Mongo/PyMongo)

I have been stuck on how to query db which the common data structure of every document looks as:
{
"_id": {
"$oid": "5e0983863bcf0dab51f2872b"
},
"word": "never", // get the `word` value for each of below queries
"wordset_id": "a42b50e85e",
"meanings": [{
"id": "1f1bca9d9f",
"def": "not ever",
"speech_part": "adverb",
"synonyms": ["ne'er"]
}, {
"id": "d35f973ed0",
"def": "not at all",
"speech_part": "adverb"
}]
}
1) query to get all the wordfor speech_part: "adverb" (eg: never,....) //
2)query to get all the word for: word length of 6 and speech_part: "adverb"
I have learnt from SO that ,to search whole collections first i have to retrieve all collections in the database , but how to write a query is where i stuck
db.collection.find({"meanings.speech_part":"adverb"},{"_id":0, "word":1})
To get array of all word of a specific speech_part above is the query.
First part of the query is filter predicate like in your scenario matching speach_part.if your matching column were not inside another object or a object inside a array, you could just write {column_name: "something"}.
as speech_part is inside an object which is inside an array, you have to write {"parentClumn.key":"something"}, in your case {"meanings.speech_part":"adverb"}.
where second part of the query is projection where you define which columns you want in your result. so to get only word column values you do {word:1}, to have more column you do {word:1, etc:1}. While mongodb project _id by default, so to remove _id from result you have to explicitly set {_id:0}
db.collection.find({
"meanings.speech_part":"adverb",
"$expr": { "$gt": [ { "$strLenCP": "$word" }, 6 ] }
},{"_id":0, "word":1})
To get array of all word of a specific speech_part with length greater than 6. This one is a bit complex query. You can look up $expr documentation. In $expr you can run function on your column and match the result. In your case strLenCP is calculating the length of your word column value and then checking, is it greater then 6 by $gt comparison operator
You may try below query to get the matching rows. You will have to try the same with pymongo.
db.getCollection('test-collection').find(
{
'meanings.speech_part': 'adverb'
},
{
_id: 0,
word: 1
}
);
Read about the projections in mongodb here:
https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results

How to make a cloudant query to find documents which two fields are equal

I need to get all documents whose e.g. "_id" field equal to another document field, e.g. "appId"
{
"_id": "xxxx-xxxx-xxxx-xxxx",
"_rev": "xxxx-xxxx-xxxx-xxxx",
"header": {
"appId": "xxxx-xxxx-xxxx-xxxx"
So what would be the query?
"selector": {
"_id": {
"$eq": header.appId
}
},
You can't do "sub queries" with Mango.
From what I see, you're trying to get all the documents listed by appId.
This could be done by using a view.
Your map function would be the following:
if(doc.header && doc.header.appId){
emit(doc.doc.header.appId,{_id: doc.header.appId});
}
The result would be a list of documents mapped by doc.header.appId.
If you query the view with ?include_docs=true, the documents would be joined to the response since we're doing a ManyToJoin join.

Why doesn't this Cloudant/couchdb $regex query work?

I am trying to pull (and delete) all records from our database that don't have a URL with the word 'box' in it. This is the query I'm using:
{
"selector": {
"$not": {
"url": {
"$regex": ".*box.*"
}
}
},
"limit": 50
}
This query returns no records. But if I remove the $not, I get all records that do have the word 'box' in the url, but that's the opposite of what I want. Why do I get no results when adding the $not?
I have tried adding a simple base to the query like "_id":{"$gte":0} but that doesn't help.
from the Cloudant doc:
You can create more complex selector expressions by combining
operators. However, for Cloudant NoSQL DB Query indexes of type json,
you cannot use 'combination' or 'array logical' operators such as
$regex as the basis of a query.
$not is a combination operator and therefore cannot be the basis of a query
i am able to get the following to work:
index
{
"index": {
"fields": ["url"]
},
"name" : "url-json-index",
"type" : "json"
}
query
{
"selector": {
"url": {
"$not": {
"$regex": ".*box.*"
}
}
},
"limit": 50,
"use_index": "url-json-index"
}
if you are still seeing problems, can you provide the output from _/explain and the indexes you have in place.
The "no results" issue is due to a bug in text indexes that has been recently fixed. However, neither $not nor $regex operators are able to take advantage of global indexes so will always result in a full database or index scan.
The way to optimise this query is to use a partial index. A partial index filters documents at indexing time rather than at query time, creating an index over a subset of the database. You then need to tell the _find endpoint to explicitly use the partial index. For example, create an index which only includes documents not matching your regex:
POST /<db>/_index
{
"index": {
"partial_filter_selector": {
"url": {
"$not": {
"$regex": ".*box.*"
}
}
},
"fields": ["type"]
},
"ddoc" : "url-not-box",
"type" : "json"
}
then at query time:
{
"selector": {
"url": {
"$not": {
"$regex": ".*box.*"
}
}
},
"limit": 50,
"use_index": "url-not-box"
}
You can see how many documents are scanned to fulfil the query in the Cloudant UI - the execution statistics are displayed in a popup underneath the query text area.
You may also find this This article about partial indexes helpful.

Pushing an item into an array of an array in MongoDB

I've been struggling with this for the last few hours and can't get it to work properly. Read all over Stackoverflow, Google and still can't implement it correctly on my case.
Basically, my document in MongoDB looks like this:
{
"_id": "H2RLYBniXZ7Fkszpu",
"userId": "FmMsoqXxJ8Nd4DRm5",
"Data": {
"name": "This is just a test.",
"summary": "sdadsdas",
"testId": "EyWcg1vS-",
"questions": [
{
"type": "test",
"key": "E1eol1DS-",
"options": []
}
],
}
}
My goal is to $push and item into the "Data.questions.options" array if that particular object's key in that array is equal to the input I request.
I tried doing this many different ways, including using the $in operator, doing things like this:
Db.fix.update({_id: "H2RLYBniXZ7Fkszpu"}, {$push: {"Data.questions.$.options": "option"}}); // Pushing the string "option" into the options array
I was also looking into the $cond operator for MongoDB to see if I can add conditionals, but it's only for aggregation. I'm not sure how to proceed with this. I'm not sure it's even possible doing this with such a nested array.
You were very close. The key part with the $ positional operator is that the array field must appear as part of the query document.
Try this:
db.Fix.update({_id: "H2RLYBniXZ7Fkszpu", "Data.questions.key":"E1eol1DS-"}, {$push: {"Data.questions.$.options": "option"}});

Dot notation vs. $elemMatch

I have a unitScores collection, where each document has an id and an array of documents like this:
"_id": ObjectId("52134edd5b1c2bb503000001"),
"scores": [
{
"userId": ObjectId("5212bf3869bf351223000002"),
"unitId": ObjectId("521160695483658217000001"),
"score": 33
},
{
"unitId": ObjectId("521160695483658217000001"),
"userId": ObjectId("5200f6e4006292d308000008"),
"score": 17
}
]
I have two find queries:
_id:new ObjectID(scoreId)
"scores.userId":new ObjectID(userId)
"scores.unitId":new ObjectID(unitId)
and
_id:new ObjectID(scoreId)
scores:
$elemMatch:
userId:new ObjectID(userId)
unitId:new ObjectID(unitId)
I would expect them to give the same result, but using the input userId and unitId of
userId: 5212bf3869bf351223000002
unitId: 521160695483658217000001
the dot notation version returns the wrong array entry (the one with score:17) and the $elemMatch returns the correct entry (the one with score:33). Why is that?
$elemMatch is not the same logic as dot notation. $elemMatch requires the same nested elements to have the values. Using dot notation allows for any nested elements to have an values. Thus, your seeing different results because the query logic is different.