Mongodb with queries in JSON format - mongodb

I was trying to solve a query given in an assessment to fetch details from a collection. The assessment was in online editor so I had to follow the base query structure.
MONGODB version 4.4
The base query was looking like below.
{
find : "MY_COLLECTION_1"
}
The collection name is "MY_COLLECTION_1", and there is field "FirstName" column in the collections like below.
{
{
"FirstName": "ABC"
}
{
"FirstName": "XYZ"
}
}
I have never seen the below format to fetch the data. Need help with this.
{
find : "MY_COLLECTION_1"
}
I tried to fetch something like below.
{
"find" : "MY_COLLECTION_1",
"FirstName" : "ABC"
}
but it's saying invalid BSON format

The "online editor" appears to be using the find database command, which has the basic structure:
{
find: <string>,
filter: <document>,
sort: <document>,
projection: <document>,
hint: <document or string>
}
You will likely need to use the filter field to pass in a query.

Related

How to find objectId as an foreign key in mongo

How can I find the value of ObjectId in whole database for any field in mongo ,
it might be use in some collections for various fields as a reference?
"fourk_runs": [{
"Objectid": "6299b9f00f09ff045cc15d"
}],
"fourk_pass_fail": [{
"Objectid": "6299b9f00f09ff045cc152"
}],
"dr_runs": [{
"Objectid": "6299b9f00f09ff045cc154"
}],
I try this command , but it does not work
db.test.find( { $text: { $search: "4c8a331bda76c559ef04" } } )
In MongoDB, the references are mostly used for the normalization process. The references from the children's table (usually an ObjectID) are then embedded in the parent table. When reading the information, the user has to perform several queries in order to retrieve data from multiple collections.
For example, we will take the next two collections, parts and products. A product will contain many parts that will be referenced in the product collection.
parts Collection:
db.parts.findOne()
{
_id : ObjectID('1111'),
partno : '7624-faef-2615',
name : 'bearing',
price: 20,000
}
products Collection:
db.products.findOne()
{
name : 'wheel',
manufacturer : 'BMW',
catalog_number: 1134,
parts : [ // array of references to Part documents
ObjectID('1111'), // reference to the bearing above
ObjectID('3f3g'), // reference to a different Part
ObjectID('234r'),
// etc
]
}
To receive the parts for a particular product, we will first have to fetch the product document identified by the catalog number:
db.products.findOne({catalog_number: 1134});
Then, fetch all the parts that are linked to this product:
db.parts.find({_id: { $in : product.parts } } ).toArray();

How does 'fuzzy' work in MongoDB's $searchBeta stage of aggregation?

I'm not quite understanding how fuzzy works in the $searchBeta stage of aggregation. I'm not getting the desired result that I want when I'm trying to implement full-text search on my backend. Full text search for MongoDB was released last year (2019), so there really aren't many tutorials and/or references to go by besides the documentation. I've read the documentation, but I'm still confused, so I would like some clarification.
Let's say I have these 5 documents in my db:
{
"name": "Lightning Bolt",
"set_name": "Masters 25"
},
{
"name": "Snapcaster Mage",
"set_name": "Modern Masters 2017"
},
{
"name": "Verdant Catacombs",
"set_name": "Modern Masters 2017"
},
{
"name": "Chain Lightning",
"set_name": "Battlebond"
},
{
"name": "Battle of Wits",
"set_name": "Magic 2013"
}
And this is my aggregation in MongoDB Compass:
db.cards.aggregate([
{
$searchBeta: {
search: { //search has been deprecated, but it works in MongoDB Compass; replace with 'text'
query: 'lightn',
path: ["name", "set_name"],
fuzzy: {
maxEdits: 1,
prefixLength: 2,
maxExpansion: 100
}
}
}
}
]);
What I'm expecting my result to be:
[
{
"name": "Lightning Bolt", //lightn is in 'Lightning'
"set_name": "Masters 25"
},
{
"name": "Chain Lightning", //lightn is in 'Lightning'
"set_name": "Battlebond"
}
]
What I actually get:
[] //empty array
I don't really understand why my result is empty, so it would be much appreciated if someone explained what I'm doing wrong.
What I think is happening:
db.cards.aggregate... is looking for documents in the "name" and "set_name" fields for words that have a max edit of one character variation from the "lightn" query. The documents that are in the cards collection contain edits that are greater than 2, and therefor your expected result is an empty array. "Fuzzy is used to find strings which are similar to the search term or terms"; used with maxEdits and prefixLength.
Have you tried the term operator with the wildcard option? I think the below aggregation would get you the results you were actually expecting.
e.g.
db.cards.aggregate([
{$searchBeta:
{"term":
{"path":
["name","set_name"],
"query": "l*h*",
"wildcard":true}
}}]).pretty()
You need to provide an index to use with your search query.
The index is basically the analyzer that your query will use to process your results regarding if you want to a full match of the text, or you want a partial match etc.
You can read more about Analyzers from here
In your case, an index based on STANDARD analyzer will help.
After you create your index your code, modified below, will work:
db.cards.aggregate([
{
$search:{
text: { //search has been deprecated, but it works in MongoDB Compass; replace with 'text'
index: 'index_name_for_analyzer (STANDARD in your case)'
query: 'lightn',
path: ["name"] //since you only want to search in one field
fuzzy: {
maxEdits: 1,
prefixLength: 2,
maxExpansion: 100
}
}
}
}
]);

Projecting nested documents in Mongo

I am trying to find and project from a nested structure. For example, I have the following document where each unit might have an embedded sub-unit:
{
"_id" : 1,
"unit" : {
"_id" : 2,
"unit" : {
"_id" : 3,
"unit" : {
"_id" : 4
}
}
}
}
And I want to get the id's of all the subunits under unit 1:
[{_id:2}, {_id:3}, {_id:4}]
$graphlookup does not seem to handle this kind of nested structure. As far as I understand, it works when the units are saved at a single level without nesting and each keep a reference to its parent unit.
What is the correct way to retrieve the desired result?
Firstly, $graphlookup isn't operator for your problem, because it's recursive search on a collection, not recursive in a document
$graphLookup Performs a recursive search on a collection, with options
for restricting the search by recursion depth and query filter.
Therefore, it didn't recursive search in your document, it only recursive search on a collection (includes multiple documents), it cannot handle your problem.
With your problem, I think it is not responsibility of Mongo, because you've retrieved your wanted document. You want to parse the retrieved document to array of sub-documents, you can do it in your language.
Example if you use JavaScript (Node.JS for backend), you can parse this document to array:
const a = {
"_id": 1,
"unit": {
"_id": 2,
"unit": {
"_id": 3,
"unit": {
"_id": 4
}
}
}
}
const parse = o => {
const { _id } = o;
if (!o.unit) return [{ _id }];
return [{ _id }, ...parse(o.unit) ];
}
console.log(parse(a.unit));
You can not do that from mongodb query. Mongodb will guarantee the document with id :1, and will not recursively search inside the document.
What you can do is: retrieve the document from mongodb, then parse it into a Map object and retrieve the information from that map, recursively.

Spring Data with Mongo: Subdocument name as query parameter

I have the following document structure:
{
"_id": "project1",
"customer": "someDefaultCustomer",
"users": {
"user1": {
"projectRoles": ["CUSTOMER"]
}
}
}
Now i'm going to query all projects with user contain 'user1' with Spring Data Mongo:
#Query("{'users.?1': {$exists : true} }")
Project findUserProject(String login);
The problem is that Spring Data escapes replacement in queries, so i've got the following 'real' query:
o.s.d.m.r.q.StringBasedMongoQuery - Created query { "users.\"user1\"" : { "$exists" : true}}
Is it possible to avoid escaping? Of course, i can create custom query using spring criteria, but i'd like to keep '#Query' approach.
Pass in the full users.user1 as the variable, i.e.:
#Query("{?1: {$exists : true} }")
If you really want to avoid people having to do that then have a helper function that adds the "users." at the start of the string then calls this method.

How to get a specific embedded document inside a MongoDB collection? [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
I have a collection Notebook which has embedded array document called Notes. The sample
document looks like as shown below.
{
"_id" : ObjectId("4f7ee46e08403d063ab0b4f9"),
"name" : "MongoDB",
"notes" : [
{
"title" : "Hello MongoDB",
"content" : "Hello MongoDB"
},
{
"title" : "ReplicaSet MongoDB",
"content" : "ReplicaSet MongoDB"
}
]
}
I want to find out only note which has title "Hello MongoDB". I am not getting what should
be the query. Can anyone help me.
You can do this with mongo version higher 2.2
the query like this:
db.coll.find({ 'notes.title': 'Hello MongoDB' }, {'notes.$': 1});
you can try with $elemMatch like Justin Jenkins
Outdated answer: See the other answers.
I don't believe what you are asking is possible, at least without some map-reduce maybe?
See here: Filtering embedded documents in MongoDB
That answer suggests you change your schema, to better suit how you'd like to work with the data.
You can use a either "dot notation" or $elemMatch to get back the correct, document that has the matching "note title" ...
> db.collection.find({ "notes.title" : "Hello MongoDB"}, { "notes.title" : 1"});
or ...
> db.collection.find({ "notes" : { "$elemMatch" : { "title" : "Hello MongoDB"} }});
But you will get back the whole array, not just the array element that caused the match.
Also, something to think about ... with your current setup it woud be hard to do any operations on the items in the array.
If you don't change your schema (as the answer linked to suggests) ... I would consider adding "ids" to each element in the array so you can do things like delete it easily if needed.
You can do this in MongoDb version 3.2+ with aggregation.
Query:
db.Notebook.aggregate(
{
$project: {
"notes": {
$filter: {
input: "$notes",
as: "note",
cond: {
$eq: [ "$$note.title", "Hello MongoDB" ]
}
}
}
}
}
)
Result:
{
"_id" : ObjectId("4f7ee46e08403d063ab0b4f9"),
"notes" : [
{
"title" : "Hello MongoDB",
"content" : "Hello MongoDB"
}
]
}
$$ used here to access the variable. I used here to access the newly created note variable inside the $filter.
You can find additional details in the official documentation about $filter, $eq and $$.
$filter: Selects a subset of an array to return based on the specified condition. Returns an array with only those elements that match the condition. The returned elements are in the original order.
$eq: Compares two values and returns true/false when the values are equivalent or not (...).
$$: Variables can hold any BSON type data. To access the value of the variable, use a string with the variable name prefixed with double dollar signs ($$).
Note:
Justin Jenkin's answer is outdated and kop's answer here doesn't return multiple documents from the collection. With this aggregation query, you can return multiple documents if needed.
I needed this and wanted to post to help someone.
You can use $ or $elemMatch. The $ operator and the $elemMatch operator project a subset of elements from an array based on a condition.
The $elemMatch projection operator takes an explicit condition argument. This allows you to project based on a condition not in the query.
db.collection.find(
{
// <expression>
},
{
notes: {
$elemMatch: {
title: 'Hello MongoDB'
}
},
name: 1
}
)
The $ operator projects the array elements based on some condition from the query statement.
db.collection.find(
{
'notes.title': 'Hello MongoDB'
},
{
'notes.title.$': 1,
name: 1
}
)
You can perform the query like this:
db.coll.find({ 'notes.title': 'Hello MongoDB' });
You can also refer to the docs for more details.