Mongodb Like one of array items - mongodb

Consider I have a collections which it's document are like this :
{
"name": "some-name",
"age": 23,
"foods" : ["pizza", "cola", "bread", "hotdog"]
}
what I need to achieve is I need to find all documents which has at least one food item which is like for example "pi".
so I want one of array items to be like search query string.

You can easily do your task using $regex.
So, using this query:
db.collection.find({
"foods": {
"$regex": "pi"
}
})
Mongo will find all documents where foods fields contains at least one item who match the regex "pi".
Example here

Related

MongoDB v5.0.5 reference existing field in updateMany()

First time using MongoDB and I'm having an issue that I would appreciate some help with please.
Let's say I have a collection called "students" with documents in the collection structured as followed:
{
"_id": ObjectId("12345"),
"Name": "Joe Bloggs",
"Class_Grade": "b"
"Homework_Grade": "c",
}
I want to create an embedded document called "Grades" that contains the class and homework grade fields and applies this to every document in the collection to end up with:
{
"_id": ObjectId("12345"),
"Name": "Joe Bloggs",
"Class_Grade": "b"
"Homework_Grade": "c",
"Grades": {
"Class_Grade": "b",
"Homework_Grade": "c",
}
}
I have been trying to achieve this using updateMany() in MongoShell:
db.students.updateMany({}, {$set: {Grades: {"Class_Grade": $Class_Grade, "Homework_Grade": $Homework_grade"}}})
However, in doing so, I receive Reference Error: $Class_Grade is not defined. I have tried amending the reference to $students.Class_Grade and receive the same error.
Your advice would be greatly appreciated
There are a few mistakes in your query,
if you want to use the internal existing field's value, you need to use an update with aggregation pipeline starting from MongoDB 4.2, you need to wrap the update part in attay bracket [], as i added query.
use quotation in field name that you want to use from internal field ex: "$Class_Grade"
you have used field $Homework_grade, and in your documents it is G is capital in Grade so try to use exact field name $Homework_Grade
db.students.updateMany({},
[
{
$set: {
Grades: {
"Class_Grade": "$Class_Grade",
"Homework_Grade": "$Homework_Grade"
}
}
}
])
Playground

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

Sort mongodb query on multiple fields

I would like to sort a mongodb query that search for bloggers.
Here the document structure (simplified) of a Blogger :
{
posts : {
hashtags : [{
hashtag : String,
weight : Number
}]
},
globalMark : Number
}
People can search bloggers via an input text. Eg: They can write "fashion travel" and click on search button.
I would like as result to show up Bloggers who have posts that contain hashtags that match /fashion/i and /travel/i, sorted by relevancy. The relevancy depends on the globalMark and hashtag weight.
I know how to show up them skipping hashtag weight but don't know how to include this weight in my query....
Here my current query :
Blogger.find({
"$and" : [{
"posts.hashtags.hashtag" : {$regex: /fashion/i}
}, {
"posts.hashtags.hashtag" : {$regex: /travel/i}
}]
})
.sort("-globalMark")
How can I handle this weight ?
BIG THANKS !
First think: MongoDB is not a for search with like operator (if your data is big you will have some latency).
Second think: hashtags value need to be object or objects in array
Third: You can use
db.collectionName.find({
$and: [
{"posts.hashtags.hashtag" : {$regex: /fashion/i}},
{"posts.hashtags.hashtag" : {$regex: /travel/i}}
]
}).sort({
globalMark: 1, "posts.hashtags.weight": 1
})
I have made it using mongodb aggregation and $project pipeline stage. Basically $project let you modify result doc so I have used it to build a score regarding different fields then sort the aggregation on this built score.
Here the doc :
https://docs.mongodb.com/manual/reference/operator/aggregation/project/

mongodb $group aggregation yields _id with multiple values as array; how to remove dupes from _id?

I am trying to conduct a very simple aggregation to collect some indexes associated with a particular owner. My query is as follows (in moped syntax):
owners = Serials.collection.aggregate([
{'$group' => {
'_id' => '$owners.owner.party_name',
'serials' => { '$addToSet' => '$serial_number' }
}}])
That's the entire function. The issue is that the 'owners.owner' field can take two forms -- it is often a nested array, with multiple party names associated with the record. But, it can also be a single record:
Form 1:
"owners": {
"owner": [
{
"entry_number": "1",
"party_name": "Company Name, LLC",
"other_fields": "other info",
},
{
"entry_number": "1",
"party_name": "Company Name, LLC",
"other_fields": "other info",
}
]
},
(yes, often the entries are repeating within the array. Sometimes it is two or more distinct owners.)
Form 2:
"owners": {
"owner": {
"entry_number": "1",
"party_name": "Another Company, Inc.",
"other_fields": "other_info",
}
},
Notice it is not embedded in an array in this case. Thus, I'm not sure an $unwind step in the aggregation process would work because the documents without an embedded array would return an error.
So anyways, the results of the aggregation yield records that look like this:
{"_id"=>["Random co.", "Random co."], "serials"=>["12345678"]}
but also records that look like this:
{"_id"=>["Company 1 co.", "Company 2 co."], "serials"=>["12345679", "12345778", "14562378", "87654321", "33822112", "11111111"]}
i.e. the 'party_name' fields are sometimes unique, but sometimes are two or more distinct strings.
My question is, how can I further refine this aggregation to remove duplicate strings from the '_id' field, and only preserve distinct values?
So, for example, in the first case the result would be:
{"_id"=>["Random co."], "serials"=>["12345678"]}
While in the second case the result would be identical.

Labelling collections in MongoDB

I have two collections: persons (millions) and groups. When creating a group I have a rule, which are actually the criteria to find persons. Now, what I want to do is to add the groups _id to all the matching persons.
The request to my API:
POST /groups {
"rule": {"age": {"$gt": 18}},
"description": "persons above 18"
}
On my MongoDB:
db.persons.find({"age": {"$gt": 18}})
Now I want to add the group _id to a groups array field in each of the matching persons, so that I can later get all persons in the group. Can this be done directly in the same query?
Maybe I'm missing something, but a simple update statement should do it:
db.persons.update(
{ "age" : {$gt : 18} },
{ $addToSet : { "groups" : groupId }},
false, // no upsert ($addToSet and $push still add the field)
true); // update multiple docs in this query
Note that $push will add the same value over and over, while $addToSet will ensure uniqueness in the array, which probably makes sense in this case.
You'll have to find/insert the group itself in a different statement, though.