$all not working in mongodb - javascript

I have two document in my collections
{ participants: [ '5ab8fcf6d8bfca2cc0aebb37', '5ab8fd15d8bfca2cc0aebb38' ],
_id: 5ab9a5a0cb274a2064b65d1b,
__v: 0
},
{ participants: [ '5ab8fcf6d8bfca2cc0aebb37', '5ab8fcf6d8bfca2cc0aebb37' ],
_id: 5ab9a5a7cb274a2064b65d1c,
__v: 0
}
and i have an array of persons like
persons = [ 5ab8fcf6d8bfca2cc0aebb37, '5ab8fcf6d8bfca2cc0aebb37' ]
Now I am trying to find a document which contains which contain participants fields similar to array persons using this query.
Participant.find({participants: {$all: persons}}).exec()
.then(connected => {
console.log(connected);
// perform some stuff
});
it throws me both document as an output.
I don't know what is the problem.
Thanx in advance.

I think what you want is the $setEquals operator.
db.collection.find({ $expr: { $setEquals: [ persons, "$participants" ] } } )
You can use the $setEquals operator with the $redact operator if the $expr operator is not available in the mongod version you're running.

you can use $eq operator as well
Participant.find( { participants: { $eq: persons } })
.then(connected => {
console.log(connected);
// perform some stuff
});
for more https://docs.mongodb.com/manual/reference/operator/query/eq/

Related

return what was not found in array in MongoDB

say my database collection has
* user collection*
[
{id:'1'}
{id:'2'}
]
I have an array of object
[
{id:'1'}
{id:'2'}
{id:'3'}
]
I want the object that was not found in the collection.
I want
[
{id:'3'}
]
I'm currently have this
const records = await dbo
.collection('user collection')
.find({
'id': { $in: newArr },
})
.toArray();
I'm a bit stumped on what to do! ... hope someone can help Thanks!
Option 1:
Looks like this is what you need via the not in operation ( $nin ) when you need to check the not exisitng id in collection documents from provided array:
db.collection.aggregate([
{
$match: {
id: {
"$nin": [
1,
2
]
}
}
},
{
$group: {
_id: null,
"idnotIntheArray": {
$push: "$id"
}
}
}
])
Explained:
$match for any documents with id not in provided array.
$group all id's in an array
plaground1
Option 2:
And this is the option where you output only the array elements not existing in the collection:
db.collection.aggregate([
{
$group: {
_id: null,
ids: {
$push: "$id"
}
}
},
{
$project: {
missingFromCollection: {
"$setDifference": [
[
1,
5,
4
],
"$ids"
]
}
}
}
])
Explained:
Push all id elements from collection to array ids ( note this solution will not allow more then 16MB total size of id's )
Use $setDifference to identify the difference between the two arrays.
playground2
You can use this aggregation:
db.entity.aggregate([
{
$match : {
"myObjList.id" : 1
}
},
{
$unwind : "$myObjList"
},
{
$match : {
"myObjList.id" : 1
}
}
])
and my aggregation result:
{
"_id" : ObjectId("6225a0f78d435fd2845f1dd1"),
"myObjList" : {
"id" : 1
}
}

mongoose get only those documents if all subdocuments pass the criteria

Let's say I have a Lesson schema and it contains an array of question subdocuments.
How would I get those lessons where it is marked as completed but all the questions in the array have isDeleted: true
I thought of something like
Lesson.find({ isComplete: true, 'questions.isDeleted': true })
but that gets the lessons if at least one of the questions is deleted. How would I assert the condition for all of the questions?
You can't use the dot notation as it flattens the array, What you can do is use $expr, this allows the use of aggregation operators, like $reduce.
Now we can iterate over the array and see if all the documents satisfy the conditions, like so:
db.collection.find({
isComplete: true,
$expr: {
$eq: [
{
$reduce: {
input: "$questions",
initialValue: 0,
in: {
$sum: [
"$$value",
{
$cond: [
{
$ne: [
"$$this.isDeleted",
true
]
},
1,
0
]
}
]
}
}
},
0
]
}
})
Mongo Playground

How to query documents by a condition on the subdocument with the latest date [duplicate]

This question already has an answer here:
Query on Last Array Value
(1 answer)
Closed 4 years ago.
I'm trying to figure out the best way to query documents based on a criteria on the latest subdocument.
So my data might look like this:
[{
_id: '59bb31efae69726bd5fc9391',
name: 'Something',
terms: [
{
_id: '58e54f5aad59a6000cdcd590',
begDate: '2017-06-13T07:00:00.000Z',
endDate: '2018-01-01T07:59:59.999Z'
},
{
_id: '59bb32765e651d28909ed706',
begDate: '2018-01-01T08:00:00.000Z',
endDate: '2019-01-01T07:59:59.999Z'
}
]
}, {
_id: '59f20ddeef426f6bca3abbf1',
name: 'Something',
terms: [
{
_id: '59f20e35c8257b5b0f22d2a6',
begDate: '2018-06-13T07:00:00.000Z',
endDate: '2019-01-01T07:59:59.999Z'
},
{
_id: '59f20e9394c8108d9db33bf9',
begDate: '2019-01-01T08:00:00.000Z',
endDate: '2020-01-01T07:59:59.999Z'
}
]
}]
What I want is to get all documents whose last term's endDate is 2019-01-01T07:59:59.999Z This could be done by either getting the last term in an array, or more reliably sorting terms, and then grabbing the last one.
I can see how I could do this with $where but I know if I can find another way it would be more performant.
I also want to add, whatever I do here would accompany other query parameters. For example:
{
_id: {
'$in': [
ObjectId("591e5e37abddad14afe1b272"),
ObjectId("591e5e37abddad14afe1b123")
]
}
}
UPDATE:
As noted, this question has a duplicate (which was hard for me to find as the question referenced is difficult to understand). That being said, I'm not only looking for the last in an array but also the most recent (I agree that's not clear in the body of the question). I'm not arguing against the duplicate question reference, but for the sake of making this easier for future readers, you'll find in the accepted answer a clean solution for mongo 3.6+ as well as a reference to another question in the comments which should help if you want to query by date in subdocuments.
Using $expr to perform a 'complex' match and $let to have an intermediate variable storing the last element of arrays found with "$arrayElemAt": [ "$terms", -1 ] in order to compare it to the date in question:
db.collection.find({
$expr: {
$let: {
vars: { "last": { $arrayElemAt: [ "$terms", -1 ] } },
in: { $eq: [ "$$last.endDate", "2019-01-01T07:59:59.999Z" ] }
}
}
})
which returns with the input you provided the first record.
And, as per your requirements, in order not to exclude the possibility to add additional filters, you can add them using $and:
db.collection.find({
$and: [
{ $expr: { $let: {
vars: { "last": { $arrayElemAt: [ "$terms", -1 ] } },
in: { $eq: [ "$$last.endDate", "2019-01-01T07:59:59.999Z" ] }
}}},
{ "_id": { $ne: "sss" } } // actually whatever additional filter
]
})
Exact same thing can be achieved with an aggregate pipeline, if you wish to perform additional stages with your matching documents:
db.collection.aggregate([
{ $match: {
$and: [
{ $expr: { $let: {
vars: { "last": { $arrayElemAt: [ "$terms", -1 ] } },
in: { $eq: [ "$$last.endDate", "2019-01-01T07:59:59.999Z" ] }
}}},
{ "_id": { $ne: "sss" } }
]
}},
{ ... }
])

Sorting Null values last in MongoDB

I'm using the following query to populate items from MongoDB, in ascending order, according to a field called sortIndex.
Sometimes though items in the DB don't have the sortIndex field. With the following query, the items with a null sortIndex are showing up at the top, and I'm wondering how to get them to show up at the bottom. Would I need two queries for this or is there a way to use one query?
.populate({path: 'slides', options: { sort: { 'sortIndex': 'ascending' } } })
You can do something like this:
db.collection.aggregate([
{ $addFields:
{
hasValue : { $cond: [ { $eq: [ "$value", null ] }, 2, 1 ] },
}
},
])
.sort({hasValue : 1, value : 1});
Duplicate of: How to keep null values at the end of sorting in Mongoose?
Anyway posting the same solution ...
Am not sure about the solution am about to say. I cant test this out as I dont have a mongo db set right now, but I think that you can use <collection>.aggregate along with $project and $sort to achieve this.
Sample code:
db.inventory.aggregate(
[
{
$project: {
item: 1,
description: { $ifNull: [ "$amount", -1*(<mimimum value>)* ] }
}
},
{
$sort : {
amount : (-1 or 1 depending on the order you want)
}
}
]
)
Hope this helps !!

mongodb find with opposite of $elemMatch

I have a collection like this:
posts = {
title: 'Hey',
content: '...',
authors: [{
id: 'id',
name: 'John'
}, {
id: 'id2',
name: 'david'
}]
};
I want to make a query. I have found the $elementMatch, but I would like the opposite.
I have also found $nin but I don't if it works for mycase.
Here is what I want to do:
db.posts.find({
authors: {
$notElemMatch: {
id: 'id'
}
}
});
I want to find every posts except those writing by someone.
You don't even need $elemMatch since you only have a single field condition. Just use $ne instead:
db.posts.find({ "authors.id": { "$ne": 'id' } });
There is a $not condition, but it really does not need apply here.
While the original question does not require the use of $elemMatch (as answered by Blakes), here is one way to "invert" the $elemMatch operator.
Use $filter + $and as a subsitute for $elemMatch and check that the result has 0 length.
$expr allows the use of aggregation expressions in simple "find" queries.
All conditions in $elemMatch will be translated to items in the array supplied as an argument to $and.
Tested to work with MongoDB server version 5.0.9
{
"$expr": {
"$eq": [
{
"$size": {
"$filter": {
"input": "$authors",
"cond": {
"$and": [
{
"$eq": ["$$this.id", "id"]
}
]
}
}
}
},
0
]
}
}
Here is a better way to "invert" the $elemMatch operator with aggregation.
Use $expr $eq and $in
$in checks if the item is in the array, since we want opposite meaning false so we check if the result of the "$in" operation is $eq (equal) to false
{
"$expr": {
"$eq": [{ "$in": { 'id', "authors.id"} }, false]
}
}

Categories

Resources