Mongo Atlas Search: Find Exact Document Matches - mongodb

Trying to use Mongo Atlas Search aggregation to find documents that precisely match my query which contains a list of 100 - 200 words.
Start of my aggregation query
{
'$search': {
'index': 'default',
'text': {
'query': 'yellow pizza blue ',
'path': 'word'
}
}
}, {...
My collection
{
"word": "yellow card"
},
{
"word": "pizza"
},
{
"word": "blue"
}
I need it to return “pizza, blue", instead it returns “yellow card, pizza, blue”

You probably just need a simple substring search using $indexOfCP
db.collection.find({
$expr: {
$ne: [
-1,
{
$indexOfCP: [
"yellow pizza blue ",
"$word"
]
}
]
}
})
Mongo Playground
If your search list is a space-separated list, you can consider $split the words field and your search list into arrays and perform $setIsSubset to find the matches.
db.collection.aggregate([
{
"$addFields": {
"searchList": "yellow pizza blue investment "
}
},
{
"$addFields": {
"searchList": {
"$split": [
"$searchList",
" "
]
},
tokens: {
"$split": [
"$word",
" "
]
}
}
},
{
"$match": {
$expr: {
"$setIsSubset": [
"$tokens",
"$searchList"
]
}
}
},
{
$unset: [
"tokens",
"searchList"
]
}
])
Mongo Playground

Related

How do I capitalize the first letter of a string in mongoDB?

I have the following document in my MongoDB:
{
name: "BRIAN"
}
I'm trying to change it to this format:
{
name: "Brian"
}
I've tried the following:
{
$project: {
name: { $concat: [ { $toLower: '$name' } ]}
}
}
So this makes the string lowercase, then I just need to make the first letter uppercase. Is it possible to do that within the same project aggregation?
As #Wernfried Domscheit suggested, you can use $substrCP to segment name and perform $toLower separately for the "tail" and keep the first character upper case. Use $concat to put back the 2 results together.
db.collection.update({},
[
{
"$addFields": {
"name": {
"$concat": [
{
"$substrCP": [
"$name",
0,
1
]
},
{
"$toLower": {
"$substrCP": [
"$name",
1,
{
"$strLenCP": "$name"
}
]
}
}
]
}
}
}
],
{
multi: true
})
Mongo Playground

Getting the position of specific words in documents in mongoDB

I’m using $indexOfCP for locating the index of some specific words.
Unfortunately, it only returns the first result. I want all the occurrences.
Plus, $indexOfCP is case sensitive and I want it to be case-insensitive.
here is an example:
db.inventory.aggregate(
[
{
$project:
{
cpLocation: { $indexOfCP: [ "$item", "foo" ] },
}
}
]
)
{ $indexOfCP: [ "cafeteria", "e" ] }
result: 3
You can use $regexFindAll which returns an array with the indexes in the key idx. So you can add an stage to get cpLocation.idx like this:
Also adding "options": "i" the regex is case insensitive.
db.collection.aggregate([
{
$project: {
cpLocation: {
"$regexFindAll": {
"input": "$item",
"regex": "e",
"options": "i"
}
},
}
},
{
"$addFields": {
cpLocation: "$cpLocation.idx"
}
}
])
Example here

MongoDB Aggregation: How to check if an object containing multiple properties exists in an array

I have an array of objects and I want to check if there is an object that matches multiple properties. I have tried using $in and $and but it does not work the way I want it to.
Here is my current implementation.
I have an array like
"choices": [
{
"name": "choiceA",
"id": 0,
"l": "k"
},
{
"name": "choiceB",
"id": 1,
"l": "j"
},
{
"name": "choiceC",
"id": 2,
"l": "l"
}
]
I am trying to write aggregation code that can check if there is an object that contains both "id":2 and "l":"j" properties. My current implementation checks if there is an object containing the first property then checks if there is an object containing the second one.
How can I get my desired results?
Below, see my aggregation query. The full code is here
db.poll.aggregate([
{
"$match": {
"_id": 100
}
},
{
$project: {
numberOfVotes: {
$and: [
{
$in: [
2,
"$choices.id"
]
},
{
$in: [
"j",
"$choices.l"
]
}
]
},
}
}
])
The above query returns true yet there is no object in the array both of the properties id:2 and "l":"J". I know the code works as expected. How can I get my desired results?
You want to use something like $elemMatch
db.collection.find({
choices: {
$elemMatch: {
id: 2,
l: "j"
}
}
})
MongoPlayground
EDIT
In an aggregation $project stage I would use $filter
db.poll.aggregate([
{
"$match": {
"_id": 100
}
},
{
$project: {
numberOfVotes: {
$gt: [
{
$size: {
$filter: {
input: "$choices",
as: "choice",
cond: {
$and: [
{
$eq: [
"$$choice.id",
2
]
},
{
$eq: [
"$$choice.l",
"j"
]
}
]
}
}
}
},
0
]
}
}
}
])
MongoPlayground

Match multiple conditions in an aggregate under expressions

sample format of document:
{
"_id": {
"$oid": "5e158e2de6facf7181cc368f"
},
"word": "as luck would have it",
}
I am trying to match multiple conditions in an expression as:
query = {
"$match": {
"$expr": {"$eq": [{"$strLenCP": "$word"}, 6],
'$lt': [
{
'$size': {
'$split': [
"$word",
" "
]
}
},
2
]
}
}
}
And pipe line as follows:
pipeline = [query]
cursor_objects = db['test'].aggregate(pipeline)
In the above query I am trying to achieve word length must be 6 and it doesn't contain any spaces
When I did this I am getting and error :
pymongo.errors.OperationFailure: An object representing an expression must have exactly one field: { $eq: [ { $strLenCP: "$word" }, 6 ], $lt: [ { $size: { $split: [ "$word", " " ]
May I know how could I achieve this ?
any help is appreciated ,...TIA
To use multiple conditions in $expr you have to use $and operator
query = {
$match: {
$expr: {
$and: [
{
$lt: [
{
$size: {
$split: ["$word", " "]
}
},
2
]
},
{ $eq: [{ $strLenCP: "$word" }, 6] }
]
}
}
};
Try this:
query = {
"$match": {
"$expr": {
$and: [{
"$eq": [{ "$strLenCP": "$word" }, 6]
}, {
'$lt': [{
'$size': {
'$split': [
"$word",
" "
]
}
},
2
]
}]
}
}
}

How to use $elemMatch query in mongodb

I tried to filter the data using $elemmatch but it's not correctly working.
My Scenario
Prod Table
[
{
id:1.
product:[
{
id:1,
name:true
},
{
id:2,
name:true
},
{
id:3,
name:false
}
]
}
]
Query
db.Prod.find(
{"product.name": true},
{_id: 0, product: {$elemMatch: {name: true}}});
I got Output
[
{
id:1.
product:[
{
id:1,
name:true
}
]
}
]
Excepted Output
[
{
id:1.
product:[
{
id:1,
name:true
},
{
id:2,
name:true
}
]
}
]
How to achieve this Scenario and I referred this Link Retrieve only the queried element in an object array in MongoDB collection and I tried all the answers in this link mentioned. but Still it's not working can give an example query.
Hmm, you probably didn't try the aggregation provided in referenced link, 'cause it perfectly works.
db.collection.aggregate([
{
$match: {
"product.name": true
}
},
{
$project: {
product: {
$filter: {
input: "$product",
as: "prod",
cond: {
$eq: [
"$$prod.name",
true
]
}
}
}
}
}
])
Will output :
[
{
"_id": 1,
"product": [
{
"id": 1,
"name": true
},
{
"id": 2,
"name": true
}
]
}
]
Here's the example.
EDIT :
From the doc :
Usage Considerations
Both the $ operator and the $elemMatch operator project the first
matching element from an array based on a condition.
Considering this, you cannot achieve what you need with a find query, but only with an aggregation query.