I have a mongoDB collection with the following objects:
{
name: "a",
email: "aaa#bestemail.com"
},
{
name: "b",
email: "bbb#bestemail123.com"
},
{
name: "c",
email: "ccc#diffemail.com"
}
I want to add to each document a field of true/false if the email address matches the /bestemail/ regex expression.
Meaning, for the current collection I would get:
{
name: "a",
email: "aaa#bestemail.com",
matching: true
},
{
name: "b",
email: "bbb#bestemail123.com",
matching: true
},
{
name: "c",
email: "ccc#diffemail.com",
matching: false
}
The main issue is that I have to work with mongo version 4.0.12 and so I cannot use $regexMatch (available from mongo 4.2)
I have tried using:
$addFields: {"matching": {$cond: [{$in: ["$email", [/bestemail/]]}, true, false]}}
but I get matching: false for all documents.
Thank you for the assistance!
I hesitate to respond since I don't have access to a MongoDB server with version 4.0.12, but perhaps this will work. [I did look at the archived docs.]
db.collection.aggregate([
{
"$addFields": {
"matching": {
"$cond": [
{
"$gt": [
{ "$indexOfCP": [ "$email", "bestemail" ] },
0
]
},
true,
false
]
}
}
}
])
Try it on the wrong server version at mongoplayground.net.
Example output:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"email": "aaa#bestemail.com",
"matching": true,
"name": "a"
},
{
"_id": ObjectId("5a934e000102030405000001"),
"email": "bbb#bestemail123.com",
"matching": true,
"name": "b"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"email": "ccc#diffemail.com",
"matching": false,
"name": "c"
}
]
Related
I would like to get all the datas from mongo while i need to replace special characters, but not rewrite the data while the query run:
data in db:
[{
number: "12/34",
type: "string"
},
{
number: "56-78",
type: "string"
},
{
number: "910*2",
type: "string"
}]
the number what I would like to query is: 1234, 5678
the related output is:
[{
number: "12/34",
type: "string"
},
{
number: "56-78",
type: "string"
}]
what I try is to add field temporary without special characters, but I cannot remove all of them because addfield doesn't handle regex. i try to do this with reduce but it's not work for me.
Anybody can help me?
With MongoDB v4.2+, you can use $regexFindAll to locate all digits. Use $reduce and $concat to reconstruct a string with special characters removed/sanitized. Perform the search on the sanitized string.
db.collection.aggregate([
{
"$addFields": {
"sanitized": {
"$regexFindAll": {
"input": "$number",
"regex": "\\d"
}
}
}
},
{
"$addFields": {
"sanitized": {
"$reduce": {
"input": "$sanitized.match",
"initialValue": "",
"in": {
"$concat": [
"$$value",
"$$this"
]
}
}
}
}
},
{
"$match": {
$expr: {
"$in": [
"$sanitized",
[
"1234",
"5678"
]
]
}
}
},
{
"$project": {
sanitized: false
}
}
])
Here is the Mongo playground for your reference.
Not able to get desired output. Getting “Unrecognized expression ‘$regex’” error
[
{
'$lookup': {
'from': 'profiles',
'let': {
'userId': '$userId',
},
'pipeline': [
{
'$match': {
$expr: {
$and: [
{ '$eq': ['$uniqueId', '$$mcontactId'] },
{
$or: [{ 'birthDate': { '$regex': '$$today' } },
{ 'spouseBirthdate': { '$regex': '$$today' } },
{ 'weddingAnniversary': { '$regex': '$$today' } },
],
},
],
},
},
},
{
'$project': {
'userId': 1,
'uniqueId': 1,
'mobileNumber': 1,
'whatsApp': 1,
'emailId': 1,
'lastName': 1,
'firstName': 1,
'address': 1,
'signature': 1,
},
},
],
'as': 'profile',
},
},
]
$regex is a query operator, you are trying to use it within an $expr which uses the "aggregation" language as oppose to the "query" language normally used within a $match stage.
Apart from that you have some other issue's in your pipeline, for example you only define $userId as a variable for the $lookup stage but in it you're trying to use $$today and $$mcontactId which are not defined anywhere.
Regardless once you sort out those issue's you have two options:
if the regex match is not related to the input variables just use $regex outside the $expr, like so:
{
'$match': {
$and: [
{
$expr: {
'$eq': [
'$uniqueId',
'$$userId',
],
},
},
{
$or: [
{
'birthDate': {
'$regex': '03-05',
},
},
],
},
],
},
},
Mongo Playground
if the regex does not to use an input variable from the $lookup then you need to use an aggregation operator, like $regexMatch to do the match within the $expr
[
{
"Name": "Dr.Soma",
"Email": "drsoma#gmail.com",
"MobNo": 111111111
},
{
"Name": "Bootha Ganesh",
"Email": "boothaganesg#gmail.com",
"MobNo": 222222222
},
{
"Name": "Steven",
"Email": "steven#gmail.com",
"MobNo": 333333333
},
{
"Name": "Dr.Anbarasi",
"Email": "anbarasi#gmail.com",
"MobNo": 4444444444
}
]
I try this to using find regex
db.details.find({Name:{$regex:/steven/i}})
output:
{
"Name": "Steven",
"Email": "steven#gmail.com",
"MobNo": 333333333
}
How to find data Name dot(.) after Soma & Space after Ganesh
Excepted Output
If I find Name Ganesh,I need
{
"Name": "Bootha Ganesh",
"Email": "boothaganesg#gmail.com",
"MobNo": 222222222
}
If I find Name small s or capital S ,I need
{
"Name": "Dr.Soma",
"Email": "drsoma#gmail.com",
"MobNo": 111111111
}
No Need Name Dr.Anbarasi data
db.collection.find({"Name": {'$regex': /\bsoma[a-zA-Z0-9]*/gi}})
\b assert position at a word boundary: (^\w | \w$ | \W\w|\w\W)
soma-for searching value
[a-zA-Z0-9]-word characters
*-to entire string
db.collection.find({ Name: { $regex: "Soma" } })
mongoplayground
db.collection.find({ Name: { $regex: ".Soma" } })
mongoplayground
db.collection.find({ Name: { $regex: " Ganesh" } })
mongoplayground
I'm trying to make a query that gets all the prices that starts with '12'.
I have a collection like this:
{
"place": "Costa Rica",
"name": "Villa Lapas",
"price": 1353,
},
{
"place": "Costa Rica",
"name": "Hotel NWS",
"price": 1948,
},
{
"place": "Costa Rica",
"name": "Hotel Papaya",
"price": 1283,
},
{
"place": "Costa Rica",
"name": "Hostal Serine",
"price": 1248,
},
And I want my results like this:
{
'prices': [
1248,
1283
]
}
I'm converting all the prices to string in order to use a regex function. But I don't understand very well how to use the regex in my query.
My query returns:
{ "prices" : null }
{ "prices" : null }
Could someone please guide me? :)
db.collection.aggregate([
{'$project': {
'_id': 0,
'price': {'$toString': '$price'}
}},
{'$project': {
'prices': {'$regexFind': { 'input': "$price", 'regex': '^12' }}
}}
]).pretty();
You are almost correct.
db.test.aggregate([
{'$project': {
'_id': 0,
'prices': {'$toString': '$price'}
^^^ -> I meant this
}},
{'$match': {
'prices': {'$regex': '^12' }
^^^ -> same here
}}
])
You need to use $match with $regex which yields the result as you expected.
If you use regexFind, it works on all matching docs and returns null where input doesn't match the pattern
And
In the first project you have price instead prices. If you refer the first project name in the second project, then pipeline matches.
In my project I store data in active record model and index html document in elasticsearch using mapper-attachments plugin. My document mapping look like this:
include Elasticsearch::Model
settings index: { number_of_shards: 5 } do
mappings do
indexes :alerted
indexes :title, analyzer: 'english', index_options: 'offsets'
indexes :summary, analyzer: 'english', index_options: 'offsets'
indexes :content, type: 'attachment', fields: {
author: { index: "no"},
date: { index: "no"},
content: { store: "yes",
type: "string",
term_vector: "with_positions_offsets"
}
}
end
end
I run a query to double check my doc mapping and the result:
"mappings": {
"feed_entry": {
"properties": {
"content": {
"type": "attachment",
"path": "full",
"fields": {
"content": {
"type": "string",
"store": true,
"term_vector": "with_positions_offsets"
},
It works great (the type: 'attachment' above). I can do the search through html doc perfectly.
I have a performance problem with activerecord which is mysql and I don't really need to store it in database so I decide to migrate to store in elasticsearch.
I am doing an experiment with elasticsearch-persistence gem.
I configure the mapping as below:
include Elasticsearch::Persistence::Model
attribute :alert_id, Integer
attribute :title, String, mapping: { analyzer: 'english' }
attribute :url, String, mapping: { analyzer: 'english' }
attribute :summary, String, mapping: { analyzer: 'english' }
attribute :alerted, Boolean, default: false, mapping: { analyzer: 'english' }
attribute :fingerprint, String, mapping: { analyzer: 'english' }
attribute :feed_id, Integer
attribute :keywords
attribute :content, nil, mapping: { type: 'attachment', fields: {
author: { index: "no"},
date: { index: "no"},
content: { store: "yes",
type: "string",
term_vector: "with_positions_offsets"
}
}
but when i do a query to mapping i got something like this:
"mappings": {
"entry": {
"properties": {
"content": {
"properties": {
"_content": {
"type": "string"
},
"_content_type": {
"type": "string"
},
"_detect_language": {
"type": "boolean"
},
which is wrong. can anyone tell me how to do a mapping with attachment type ?
Really appreciate your help.
In the mean time, I have to hard-code it this way:
def self.recreate_index!
mappings = {}
mappings[FeedEntry::ELASTIC_TYPE_NAME]= {
"properties": {
"alerted": {
"type": "boolean"
},
"title": {
#for exact match
"index": "not_analyzed",
"type": "string"
},
"url": {
"index": "not_analyzed",
"type": "string"
},
"summary": {
"analyzer": "english",
"index_options": "offsets",
"type": "string"
},
"content": {
"type": "attachment",
"fields": {
"author": {
"index": "no"
},
"date": {
"index": "no"
},
"content": {
"store": "yes",
"type": "string",
"term_vector": "with_positions_offsets"
}
}
}
}
}
options = {
index: FeedEntry::ELASTIC_INDEX_NAME,
}
self.gateway.client.indices.delete(options) rescue nil
self.gateway.client.indices.create(options.merge( body: { mappings: mappings}))
end
And then override the to_hash method
def to_hash(options={})
hash = self.as_json
map_attachment(hash) if !self.alerted
hash
end
# encode the content to Base64 formatj
def map_attachment(hash)
hash["content"] = {
"_detect_language": false,
"_language": "en",
"_indexed_chars": -1 ,
"_content_type": "text/html",
"_content": Base64.encode64(self.content)
}
hash
end
Then I have to call
FeedEntry.recreate_index!
before hand to create the mapping for elastic search. Becareful when you update the document you might end up with double base64 encoding of the content field. In my scenario, I checked the alerted field.