MongoDB Regex $and $or Search Query - mongodb

I am trying to construct a query that will accept multiple fields that can be searched over using regex for partial field matching that also has a hard constraint on other fields.
Example:
Collection: "Projects"
Required Information: { propertyId: "abc", clientId: "xyz" }
Fields to be Searched: name, serviceType.name, manager.name
Currently, I have a query like this, but if there are no results it returns all the results, which isn't helpful.
{
'$and': [
{ propertyId: '7sHGCHT4ns6z9j6BC' },
{ clientId: 'xyz' },
{ '$or':
[
{ name: /HVAC/gi },
{ 'serviceType.name': /HVAC/gi },
{ 'manager.name': /HVAC/gi }
]
}
]
}
If anyone has any insight into this it would be much appreciated.
Example Document:
{
_id: "abc",
propertyId: "7sHGCHT4ns6z9j6BC",
clientId: "xyz"
name: "16.000.001",
serviceType: {
_id: "asdf",
name: "HVAC"
},
manager: {
_id: "dfgh",
name: "Patrick Lewis",
}
}
The expected result is to only find documents where propertyId = 7sHGCHT4ns6z9j6BC AND one at least one of the following keys: name, serviceType.name, or manager.name match an inputted string, in this case, it's HVAC and if none of the regex fields match, then return nothing.
UPDATE
The issue was with MongoDB, after restarting it, everything worked.

Try following script:
db.collection.find({
$and:[
{propertyId:"7sHGCHT4ns6z9j6BC"},
{
$or:[
{name: /HVAC/i},
{"serviceType.name": /HVAC/i},
{"manager.name": /HVAC/i}
]
}]
})
Query above will return a document or documents if and only if propertyId matches and either of name, serviceType.name or manager.name matches desired regex.

Related

Upserting nested fields with a dot(.) in key in MongoDB

I have query in MongoDB for which I'm trying to upsert an inner nested attribute that contains a dot(.) in the key. E.g. a document might look something like: (below is a fictitious example just to highlight the constraint I'm facing.)
const person = {
name: 'Peter',
address: {
'NY.postalCode': 12345,
'CA.postalCode': 23456,
}
}
However, when I try to update one of the nested attribute in address with the below $set operation, I get an additional object NY under address and its subKey postalCode as a result, instead of the flattened attribute within address.
await Person.findByIdAndUpdate(id, {
$set: {
'address.NY.postalCode': 98765,
}
}, { new: true });
// Output
{
name: 'Peter',
address: {
'NY.postalCode': 12345,
'CA.postalCode': 23456,
NY: {
postalCode: 98765,
}
}
}
I've tried using the escape character for dot (\u002e), but get the same output. Also, I have seen some new features for setting fields but only in Mongo v5: https://www.mongodb.com/docs/manual/reference/operator/aggregation/setField/#mongodb-expression-exp.-setField. However, we're using Mongo v4.2 and would not be able to upgrade until a while later.
Would like to check if there are any means to $set nested attributes in address that don't completely replace the address object? i.e. to be able to specifically upsert an inner attribute within address object?
For example, is it possible to use the aggregation framework to workaround this?
I've tried something like the below, but it didn't work - not sure if its something that I did wrong or its probably not possible to use the aggregation pipeline..
Person.aggregate([
{
$match: {
_id: id,
},
},
{
$replaceRoot: { newRoot: {
$mergeObjects: [
'$$ROOT.address',
{
'NY.postalCode': 98765,
},
],
} },
},
]);
For your scenario, you need to achieve the update with aggregation pipeline.
Use $literal to escape the field name with dot.
Via $mergeObjects to merge current address object with { NY.postalCode': 98765 }.
db.collection.update({
"_id": ObjectId("5a934e000102030405000000")
},
[
{
$set: {
"address": {
$mergeObjects: [
"$address",
{
$literal: {
"NY.postalCode": 98765
}
}
]
}
}
}
],
{
new: true
})
Demo # Mongo Playground

mongodb - how to insert a new key/value on each array's element if not present (with mongo query)

I would like to update each elements (object) in an array of a company.
Here my actual data :
{
_id: ObjectId("60d31024860ce0400b586111")
contracts:
[
{
name: 1.pdf
url: "https://someurl"
createdAt: 2021-06-23T10:42:44.594+00:00
}
{
name: 2.pdf
url: "https://someurl"
}
{
name: 3.pdf
url: "https://someurl"
}
]
}
I would like to add a defined date on each object (in contracts) that has no "updatedAt" key.
Here what I tried :
db.companies.update({ _id: ObjectId("60d31024860ce0400b586111"),"contracts.createdAt": { $exists: false } },{ $set: { "contracts.$.createdAt": "test" } })
but I got this error :
"The positional operator did not find the match needed from the query."
I have also tried this and it works, but I don't wanna query by file name. I just wanna add "createdAt" on each elements found that has no "createdAt"
db.companies.update({ "contracts.name": "2.pdf" },{ $set: { "contracts.$.createdAt": "atest" } })
I think you need to use the filtered position operator:
$ - updates the first matched array element
$[] - updates all the matched elements with a specific condition
The specific condition is mentioned in the arrayFilters key.
db.students.update(
{ },
{ $set: { "contracts.$[element].createdAt" : "atest"} },
{ multi: true,
arrayFilters: [ { "element.createdAt": { $exists: false } } ]
}
)
multi - true is to apply the operation on all the matching documents.
Also notice, how the first query parameter is empty, which means the query runs for all documents. I used it based on the second query you wrote but you can also add in an ObjectID query there.

MongoDB / Mongoose - Return only array items that matches $text

I have the following object:
user: {
_id: "xxx",
name: "Lucas",
items: [
{ name: "shoes", description: "nice shoes" },
{ name: "pants", description: "old pants" },
],
places: [
{name: "my house", loc: { type: "Point", coordinates: [-27, -43] }}
]
}
I need to perform a text-search ($text) that returns only the items.
For example:
await User.find({ $text: { $search: "shoes" } });
This works! But it also returns pants, since it returns the user and not only the array item. And that is the problem, i need to paginate over the items in my database. So I need to return only the array items that matches the $text search. I know that if items was a collection itself it would work, but in my case I need those inside the user because I combine $text for items and $geoWithin for places.
So, how do I return the User keeping only his items that matched my $text search?
Did you try to use regex
To include a regular expression in a comma-separated list of query conditions for the field, use the $regex operator. For example:
{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } }
or smth like
db.users.find({"name": /^m/})
https://docs.mongodb.com/manual/reference/operator/query/regex/

How to update multiple elements of a single array in mongoDB

I have a document of mongoDb like following
{
_id: "c4bYJWz42T2JzbmHh",
DATA:[
{sno:1, name: xyz, country: xyz},
{sno:2, name: xyz1, country: xyz1},
{sno:3, name: xyz2, country: xyz2}
]
}
Now i want to update name and country on basis of 'sno'.I have used this approach
ExampleDb.update({
_id: data.id
}, {
$set: {
"DATA.$[elem].name": data.name ,
"DATA.$[elem].country" :data.country
}
},
{
arrayFilters: [ { "elem.sno": data.sno } ]
});
ut seems worng as it show following error.
Exception while invoking method 'ExampleDb.update' MongoError: Modifiers operate on fields but we found a Array instead.

What is the better implementation? MongoDb Query

I need some help with MongoDb. I need to check if an object exists in the database. If it's true, then I need to check if this object has a specific element into array (Products). If not, I need to create this object(Order) with this element(Cookie) in to array(Products).
Example data:
Order {
_id: ObjectId("580bc55f54101f1d18152d88"),
code: "AVG223424",
products: [
{
name: "Cookie"
},
{
name: "Soda"
}
]
}
Finally, what is the better implementation?
Assuming you are using a collection with the name 'Orders'
db
.Orders
.update({
code: "12345"
}, {
$addToSet: {
products: {
name: "Cookie"
}
},
$setOnInsert: {
code: "12345"
}
}, {
upsert: true
});
This query looks for a document with the same 'code,' and if found, will add the object '{name: "Cookie"}' if there is no other Object with the same key/val pairs. If the document does not exist, the '$setOnInsert' command will set the specified fields only if a new document is created.