Query finding a group whose members match exactly with a given string - mongodb

First of all, my English is not good, I apologize if I am rude.
I need your help with a query. I tried many things but failed.
I’ve written a little database example below.
I want to find the group whose members match exactly with the given username array.
groups.findOne( { 'members.username': { $in: [ 'john22', 'david7' ] } } )
As a result, the first group is returning. But there is another user in the first group. Whereas the array matches exactly with the second group. How should I write the query for exact match. Please help me.
Thank you
{ groups: [
{
id:1,
name:"aliens",
members:[
{
username:"john22",
joineddate:222222222,
removed: false
},
{
username:"david7",
joineddate:3333333333,
removed: false
},
{
username:"william4",
joineddate:444444444444,
removed: false
},
]
},
{
id:2,
name:"stars",
members:[
{
username:"john22",
joineddate:111111111111,
removed: false
},
{
username:"david7",
joineddate:111111111111,
removed: false
},
]
}
] }

Related

MongoDB: Update array elements on multiple conditions

Colleagues, good afternoon!
I'm struggling with some issue. I am using MongoDB 4.4.4. My assignment looks like this:
There is a set of elements methods[].subcategories[].actions[]. Please note that all objects are arrays and they may be absent. Elements of the actions[] array consists of the _id and title fields.
It is necessary to find the actual value of recordId by the field actions.title of the element and write it to the element of the actions array.
List of current values:
0af4cd2e-78cb-109b-8178-d5a7ba0e0012, Inspection
0af4cd2e-78cb-109b-8178-d5a7ba130014, Screening
0af4cd2e-78cb-109b-8178-d5a7ba170016, Poll
0af4cd2e-78cb-109b-8178-d5a7ba1b0018, Getting written explanations
0af4cd2e-78cb-109b-8178-d5a7ba1e001a, Request for documents
0af4cd2e-78cb-109b-8178-d5a7ba21001c, Sampling (samples)
0af4cd2e-78cb-109b-8178-d5a7ba23001e, Instrumental examination
0af4cd2e-78cb-109b-8178-d5a7ba260020, Test
0af4cd2e-78cb-109b-8178-d5a7ba2b0022, Expertise
0af4cd2e-78cb-109b-8178-d5a7ba2d0024, Experiment
3b7205c1-8282-4b63-8121-b82aacd7ca67, Request for documents that, in accordance with the mandatory requirements, must be located at the location (carrying out activities) of the controlled person (its branches, representative offices, separate structural divisions) or the object of control
I wrote the following code:
db.getSiblingDB("ervk_core").getCollection("supervision1").updateMany(
{},
{
"$set": {
"methods.subcategories.actions.$[elem1]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0012",
"methods.subcategories.actions.$[elem2]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0014",
"methods.subcategories.actions.$[elem3]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0016",
"methods.subcategories.actions.$[elem4]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0018",
"methods.subcategories.actions.$[elem5]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001a",
"methods.subcategories.actions.$[elem6]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001c",
"methods.subcategories.actions.$[elem7]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001e",
"methods.subcategories.actions.$[elem8]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260020",
"methods.subcategories.actions.$[elem9]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260022",
"methods.subcategories.actions.$[elem10]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260024",
"methods.subcategories.actions.$[elem11]._id": "3b7205c1-8282-4b63-8121-b82aacd7ca67",
}
},
{
"arrayFilters": [
{
"elem1.title": "Inspection",
},
{
"elem2.title": "Search",
},
{
"elem3.title": "Poll",
},
{
"elem4.title": "Receipt of Written Explanations",
},
{
"elem5.title": "Retrieval of Documents",
},
{
"elem6.title": "Sampling (samples)",
},
{
"elem7.title": "Instrumental examination",
},
{
"elem8.title": "Trial",
},
{
"elem9.title": "Expertise",
},
{
"elem10.title": "Experiment",
},
{
"elem11.title": "Request for documents that, in accordance with the mandatory requirements, must be located at the location (carrying out activities) of the controlled person (its branches, representative offices, separate structural divisions) or the object of control",
}
]
}
);
However, it gives the error "The path 'methods.subcategories.actions' must exist in the document in order to apply array updates.". I understand why it occurs - due to the absence of the actions[] array. But how can I account for the fact that methods[].subcategories[].actions[] arrays may be missing. And did I write the code correctly, otherwise I'm already a little confused. Thanks a lot in advance!
What you can do is add array filters checks to the method and subcategory object to see the nested array exists, this will solve your issue as Mongo will not continue checking the nested conditions in case they don't exist. Here's how you'd do it:
db.collection.updateMany(
{
"methods.subcategories.actions": {
$exists: true
}
},
{
"$set": {
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem1]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0012",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem2]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0014",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem3]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0016",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem4]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e0018",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem5]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001a",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem6]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001c",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem7]._id": "0af4cd2e-78cb-109b-8178-d5a7ba0e001e",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem8]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260020",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem9]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260022",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem10]._id": "0af4cd2e-78cb-109b-8178-d5a7ba260024",
"methods.$[methodElem].subcategories.$[subCatElem].actions.$[elem11]._id": "3b7205c1-8282-4b63-8121-b82aacd7ca67"
}
},
{
"arrayFilters": [
{
"methodElem.subcategories": {
$exists: true
}
},
{
"subCatElem.actions": {
$exists: true
}
},
{
"elem1.title": "Inspection"
},
{
"elem2.title": "Search"
},
{
"elem3.title": "Poll"
},
{
"elem4.title": "Receipt of Written Explanations"
},
{
"elem5.title": "Retrieval of Documents"
},
{
"elem6.title": "Sampling (samples)"
},
{
"elem7.title": "Instrumental examination"
},
{
"elem8.title": "Trial"
},
{
"elem9.title": "Expertise"
},
{
"elem10.title": "Experiment"
},
{
"elem11.title": "Request for documents that, in accordance with the mandatory requirements, must be located at the location (carrying out activities) of the controlled person (its branches, representative offices, separate structural divisions) or the object of control"
}
]
})
Mongo Playground
I also changed the updates query to just ignore documents with no nested actions, this is just to save time.

How can I update a property within an array of objects based on it's existing value in Mongo?

I have some documents with the following structure...
{
user: "Joe",
lists: [
{ listId: "1234", listName: "dogs" },
{ listId: "5678", listName: "cats" }
]
}
I am trying to prepend a string to each listId field but I am stuck. Amongst other things I have tried...
db.users.updateMany(
{"lists.listId": /^[0-9a-f]{20,}$/},
[{$set:
{"lists.listId.$[]": {"$concat": ["0000", "$lists.listId"]}}
}]
)
But I got the error message: "FieldPath field names may not start with '$'"
Variations on this write results into the appropriate field, but not the results I'm after.
I've bashed my head against the docs for a few hours now but all the references I can find to using the positional operator to reference the value of the field that is being updated use the field name directly, not referenced as a property like I am doing. I've not really messed with pipelines a lot before and I'm finding it all a bit confusing! Someone kindly helped me with a closely related problem yesterday, using $map, and that worked great for a plain array of strings but I haven't had any luck adapting that to an array of objects with string properties. Sorry if this is Mongo 101, the docs are good, but there's a lot of them and I'm not sure which bits are relevant to this.
You can do it like this:
db.collection.users({},
[
{
"$set": {
lists: {
$map: {
input: "$lists",
in: {
$mergeObjects: [
{
"listName": "$$this.listName",
"listId": {
$concat: [
"0000",
"$$this.listId"
]
}
}
]
}
}
}
}
}
],
{
"multi": true
})
Here is the working example: https://mongoplayground.net/p/Q8kUTB6X5JY

MongoDB not using wildcard nested array index

I have the following collection:
{
_id: 12345,
quizzes: [
{
_id: 111111,
questions: []
}
]
},
{
_id: 78910,
quizzes: [
{
_id: 22222
}
]
}
I want to select the documents of a certain quiz from the quizzes that do not have the questions array and want to make sure that it uses the appropriate questions index. So I use the following query:
Answer.find({ 'quizzes.0.questions': { $exists: false } }).explain('queryPlanner');
Which returns:
{
queryPlanner: {
plannerVersion: 1,
namespace: 'iquiz.answers',
indexFilterSet: false,
parsedQuery: { 'quizzes.0.questions': [Object] },
winningPlan: { stage: 'COLLSCAN', filter: [Object], direction: 'forward' },
rejectedPlans: []
}
}
The query is not using any index as seen from the output. I have tried the following indexes and none get used:
{ quizzes.$**: 1 }
{ quizzes.questions: 1 }
{ quizzes.[$**].questions: 1 }
{ quizzes: 1 }
The only 1 that actually gets used:
{ quizzes.0.questions: 1 }
However this is not really practical as I may target any quiz from the quizzes array not just the first one. Is there a certain syntax for the index in my case or this is a current limitation of mongodb? Thanks!
Indexes generally do not help to answer queries in the form of "X does not exist". See also mongodb indexes covering missing values.
To verify whether the index is used, look up some data using a positive condition.

MongoDB $addToSet inside another $addToSet

I am trying to achieve the below response from query.
{
users:[
user:{
name:"",
email:[
]
},
....user2
]
}
I have something similar to below.
I will put this way. One user can have n number of devices. He may have more than one email per device. I want to group at devices. And user field should have common information for that device. As we think, name will always be same. Device specific attributes also needed like whatKindOfDevice, howManyIssuesAreThereInThatDevice, howManyCanBeAddressedByUpgrade, howManyAreRare,etc.. along with this i need to get all the emails used in that device like owner,user,associate - all emails put.
Think my document Id is not associated with single user, single device. One user can have any number of devices. One device can have n Number of documents.
$group:{
"_id":"user_device_id",
"user": {
"$addToSet": {
"name":"$name",
"deviceName":"$deviceName",
"email": {"$addToSet":{}} //Something Similar I am expecting
}
}
}
If I add email outer user it works - but it affects the response format required.
Is it possible or any other way to get it the similar response through the query?
Let's assume one user can have more than one document. In each doc, there could be same or duplicate email IDs. I am trying to get that together.
Please advise.
Sample Doc:
{
_id:ObjectId,
name:"user1",
email:"a#yahoo.com"
},
{
_id:ObjectId,
name:"user1",
email:"a#device.com"
},
..user2Doc
..user1Doc with another category, duplicate email i.e a#yahoo.com
..user2Doc with new email
..
Well, it seems like you want to get all the email for the particular user and then group all the users.
So, to achieve that you have to do consecutive grouping stages.
I used the below documents:
[
{
name:"user1",
email:"a#yahoo.com"
},
{
name:"user1",
email:"a#device.com"
},
{
name:"user2",
email:"b#yahoo.com"
},
{
name:"user1",
email:"c#device.com"
}
]
Here is the query:
db.collection.aggregate([
{
$group:{
"_id":"$name",
"emails":{
$addToSet:"$email"
},
"name":{
$first:"$name"
}
}
},
{
$group:{
"_id":null,
"users":{
$addToSet:{
"name":"$name",
"email":"$emails"
}
}
}
},
{
$project:{
"_id":0
}
}
]).pretty()
Output:
{
"users" : [
{
"name" : "user1",
"email" : [
"c#device.com",
"a#device.com",
"a#yahoo.com"
]
},
{
"name" : "user2",
"email" : [
"b#yahoo.com"
]
}
]
}
For mare about $group refer here.
Hope this will help :)

MongoDB Regex $and $or Search Query

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.