MongoDB - Select where array contains a document field - arrays

The documents in my collection("users") look like this:
{
_id: ObjectID(...),
verifiedFields:
{
email: ["user#example.com", "othermail#example.com"],
phone: [...]
},
profiles:
[
{
_id: ObjectID(...),
fields:
{
email: { value: "user#example.com" }
}
}
]
}
I would like to now select all users who's profiles.field.email.value is contained within their verifiedFields.email. I would like to avoid having to store a boolean verified as the user should be allowed to have multiple profiles with the same fields and this would cause complications later on.
Thanks in advance!

Your query is:
db.users.find({
$expr: {$gt: [{$size: {$setIntersection: ['$profiles.fields.email.value', '$verifiedFields.email']}}, 0]}
})
This query doesn't use indexes, so on performance issue you will need add verified field.
Please, check aggregation pipeline and $expr for better understanding this query. Pipeline used for testing your query was:
db.test.aggregate([
{ $addFields: {a : '$profiles.fields.email.value'}},
{ $addFields: {b: { $setIntersection: ['$a', '$verifiedFields.email']}}},
{ $match: {$expr: {$gt: [{$size: '$b'}, 0]}}}
])

something like this should work:
collection('users').find({
'profiles[0].fields.email.value': {$in: 'verifiedFields.email'}
})

Related

Mongo DB aggregation on array

im trying to add element to array in document MongoDB collection with Aggregate (not regular update) match to specific name
but i dont find the right syntax
for example:
{"name":"TEST1","department":"T1","skills":["JS","HTML"],"expY":5}
{"name":"TEST2","department":"T2","skills":["Java","CSS"],"expY":3}
i want to add to skills array "CSS" i try with sort, match, group, project, ($add, $push etc) and none of those syntax not working
db.collection.aggregate([
{ $match : { name : "TEST1" } },
HERE I DONT KNOW WHAT IS THE RIGHT SYNTAX TO ADD ELEMENT TO skills array
])
If I am understading your question correctly, you want to match all the documents with name "TEST1" and then add "CSS" to the skills array. If that's correct, here is one way to do that:
db.collection.aggregate([
{
$match: {
name: "TEST1"
}
},
{
$project: {
name: "$name",
department: "$department",
expY: "$expY",
skills: {
$concatArrays: [
"$skills",
[
"CSS"
]
]
}
}
}
])
Playground
Here is how to update your document to add "CSS" to the array:
db.your_collection.update({ name : "TEST1" }, { $push: { skills: 'CSS' } })

How to filter documents by multiple conditions on Array of Objects in MongoDB

Suppose, I have a collection in which each document looks like following:
Is it possible to find all documents of this collection based on following multiple conditions on Objects in modules array.
{_id: OID123, status: available} and {_id: OID456, status: complete}
So that, it should return document similar to following:
{modules: [{_id: OID123, status: available}, {_id: OID456, status: complete}, {_id: OID789, ...}] }
Schema/Configuration on Mongo playground for this problem
Thank You everyone!
I managed to solve this problem by following query using $all operator:
db.collection.find({
"modules": {
$all: [
{
$elemMatch: {
"_id": "OID1",
"status": "available"
}
},
{
$elemMatch: {
"_id": "OID2",
"status": "complete"
}
}
]
}
})
You can find more details on the mentioned playground link:
Mongo playground link with Query and example schema for this problem

Mongo error - Can't canonicalize query: BadValue Unsupported projection option

I am new to MongoDB and trying to execute a query. I have a company collection and company IDs array. I would like to get the results where attributes.0.ccode exist and attributes.0.ccode is not empty and will be checked within the ids provided in an array( cdata)
var query = Company.find({ _id: { $in: cdata } },{ "attributes.0.ccode": { $exists: true }, $and: [ { "attributes.0.ccode": { $ne: "" } } ] }).select({"attributes": 1}).sort({});
The error I am getting is
"$err": "Can't canonicalize query: BadValue Unsupported projection option: attributes.0.ccode: { $exists: true }",
"code": 17287
I think it's a bracketing issue but can't figure it out where.
Any help is highly appreciated.
In your code { _id: { $in: cdata } } is interpreted as query, and everything else, starting from ,{ "attributes.0.ccode": { $e.. as a Projection (which field to display). Try to refactor your code so _id: {$in ...} and the rest of the query belong to the same higher - level object. Something like this:
var query = Company.find({
_id: {
$in: cdata
},
"attributes.0.ccode": {
$exists: true
},
$and: [
{
"attributes.0.ccode": {
$ne: ""
}
}
]
}).select({"attributes": 1}).sort({});

mongodb select parent subdocument based on child subdocument's array

I'm trying to get a list of all Mary Mack's shifts from the volunteers collection but I keep getting back either nothing or everything. Can someone please help me? I've tried several ways, some are listed below.
I'd like the data to look like:
where date time details
__________________________________________________________
Registration 2017-06-24 8AM - NOON check people in
I've got volunteers data that looks like this:
{
where: "Registration",
description: "blah blah blah",
shifts: [{
dateNeeded: "2017-06-24",
timeslot: "8AM - NOON",
details: "check people in",
volunteers: [{
name: "Mary Mack",
phone: 1234567890,
email: "mary#mack.com"
}]
}]
}
I've tried:
Volunteer.find({"shifts.volleyteers.email": "mary#mack.com" }, { "shifts.$": 1, "where": 1 })
I've also tried aggregation and filtering:
Volunteer
.aggregate(
{$project: {where:1, shifts:1}},
{$unwind: "$shifts"})
You can try below aggregation query
$match to find documents with volunteers email
$project with $arrayElemAt to convert the shift array to document followed by $let to map the output fields.
aggregate({
$match: {
"shifts.volunteers.email": "mary#mack.com"
}
}, {
$project: {
where: 1,
shifts: {
$let: {
vars: {
doc: {
$arrayElemAt: ["$shifts", 0]
}
},
in: {
date: "$$doc.dateNeeded",
time: "$$doc.timeslot",
details: "$$doc.details"
}
}
}
}
})
You can also add extra $project stage instead of $let operator.
aggregate({
$match: {
"shifts.volunteers.email": "mary#mack.com"
}
}, {
$project: {
where: 1,
shift: {
$arrayElemAt: ["$shifts", 0]
}
}
}, {
$project: {
where: 1,
date: "$shift.dateNeeded",
time: "$shift.timeslot",
details: "$shift.details"
}
})

Filtering an embedded array in MongoDB

I have a Mongodb document that contains an an array that is deeply imbedded inside the document. In one of my action, I would like to return the entire document but filter out the elements of that array that don't match that criteria.
Here is some simplified data:
{
id: 123 ,
vehicles : [
{name: 'Mercedes', listed: true},
{name: 'Nissan', listed: false},
...
]
}
So, in this example I want the entire document but I want the vehicles array to only have objects that have the listed property set to true.
Solutions
Ideally, I'm looking for a solution using mongo's queries (e.g. `$unwind, $elemMatch, etc...) but I'm also using mongoose so solution that uses Mongoose is OK.
You could use aggregation framework like this:
db.test312.aggregate(
{$unwind:"$vehicles"},
{$match:{"vehicles.name":"Nissan"}},
{$group:{_id:"$_id",vehicles:{$push:"$vehicles"}}}
)
You can use $addToSet on the group after unwinding and matching by listed equals true.
Sample shell query:
db.collection.aggregate([
{
$unwind: "$vehicles"
},
{
$match: {
"vehicles.listed": {
$eq: true
}
}
},
{
$group: {
_id: "$id",
vehicles: {
"$addToSet": {
name: "$vehicles.name",
listed: "$vehicles.listed"
}
}
}
},
{
$project: {
_id: 0,
id: "$_id",
vehicles: 1
}
}
]).pretty();

Resources