MongoDB - How to get an exact query data using $all - mongodb

I try to query data from MongoDB using this line of code:
forms = await AllForm.find({
answers: {
$all: [{ $elemMatch: { dateCreate: "2022-10-25" } }],
},
It was supposed to return dates that are only "2022-10-25", but it turns out that it selected all the dates with the result below:
"status": true,
"message": "LIST_FORM",
"forms": [
{
"_id": "635711356b220b918529c29a",
"formId": "635711356b220b918529c298",
"title": "Quality",
"department": "Quality",
"answers": [
{
"username": "jansenstan24sdasa#gmail.com",
"dateCreate": "2022-10-25",
"Keterangan": "john#nabas.com",
"Jam_Kerja": "14:09"
},
{
"username": "jansenstan2410#gmail.com",
"dateCreate": "2022-10-24",
"Keterangan": "john#dose.com",
"Jam_Kerja": "10:50"
}
],
"createdAt": "2022-10-24T22:27:01.673Z",
"updatedAt": "2022-10-24T22:32:27.683Z",
"__v": 0
},
{
"_id": "63571d2285d6fb180cfa9f84",
"formId": "63571d2285d6fb180cfa9f82",
"title": "Quality_2",
"department": null,
"answers": [
{
"username": "jansenstan24#gmail.com",
"dateCreate": "2022-10-25",
"Test": "john#nabatisnack.com",
"Date": "2022-10-12T00:00:00.000Z"
},
{
"username": "jansenstan24#gmail.com",
"dateCreate": "2022-10-25",
"Test": "john#nabatisnack.com",
"Date": "2022-10-12T00:00:00.000Z"
}
],
"createdAt": "2022-10-24T23:17:54.995Z",
"updatedAt": "2022-10-24T23:19:29.981Z",
"__v": 0
}
]
Can someone please tell me where did I do wrong with the query?

Think that the .find() query unable to complete such a complex projection.
You may look for aggregation query.
$match - With dot notation, find the document(s with forms array contain the document with dateCreate is "2022-10-25" in nested answers array.
$set - Set the answers array.
2.1. $filter - Filter the matched document in the answers array.
forms = await AllForm.aggregate([
{
$match: {
"answers.dateCreate": "2022-10-25"
}
},
{
$set: {
answers: {
$filter: {
input: "$answers",
cond: {
$eq: [
"$$this.dateCreate",
"2022-10-25"
]
}
}
}
}
}
])
Demo # Mongo Playground

Related

MongoDB Aggregation - Change a value of field based on other field value in deeply nested array of objects

So I have a number of documents in my collection. Each object is a user object which contains thoughts and thoughts have replies. What I want is when a reply has anonymous true, its username value should say anonymous instead of the username value.
Document
[
{
"_id": {
"$oid": "6276eb2195b181d38eee0b43"
},
"username": "abvd",
"password": "efgh",
"thoughts": [
{
"_id": {
"$oid": "62778ff975e2c8725b9276f5"
},
"text": "last thought",
"anonymous": true,
"replies": [
{
"_id": {
"$oid": "62778fff75e2c8725b9276f5"
},
"text": "new reply",
"anonymous": true,
"username": "cdf"
},
{
"_id": {
"$oid": "62778fff75e2c8725b9276f5"
},
"text": "new reply",
"anonymous": false,
"username": "cdf"
}
]
}
]
}
]
Output Required. If you see the value in username says anonymous even though the existing document has "cdf" as the value
[
{
"_id": {
"$oid": "6276eb2195b181d38eee0b43"
},
"username": "abvd",
"password": "efgh",
"thoughts": [
{
"_id": {
"$oid": "62778ff975e2c8725b9276f5"
},
"text": "last thought",
"anonymous": true,
"replies": [
{
"_id": {
"$oid": "62778fff75e2c8725b9276f5"
},
"text": "new reply",
"anonymous": true,
"username": "anonymous"
},
{
"_id": {
"$oid": "62778fff75e2c8725b9276f5"
},
"text": "new reply",
"anonymous": false,
"username": "cdf"
}
]
}
]
}
]
Let me know if you know how to help.
Here's a MongoDB Playground URL containing the existing document:
https://mongoplayground.net/p/WoP-3z-DMuf
A bit complex query.
$set - Update the thoughts field.
1.1. $map - Iterate each thought document and return new document from 1.1.1.
1.1.1. $mergeObjects - Merge objects for thoughts document and replies array from 1.1.1.1.
1.1.1.1. $map - Iterate the reply document, return the new document by merging reply document and username field with updating its value based on the anonymous field via $cond.
db.collection.aggregate([
{
$set: {
thoughts: {
$map: {
input: "$thoughts",
as: "thought",
in: {
$mergeObjects: [
"$$thought",
{
replies: {
$map: {
input: "$$thought.replies",
as: "reply",
in: {
$mergeObjects: [
"$$reply",
{
username: {
"$cond": {
"if": "$$reply.anonymous",
"then": "anonymous",
"else": "$$reply.username"
}
}
}
]
}
}
}
}
]
}
}
}
}
}
])
Sample Mongo Playground

Delete objects that met a condition inside an array in mongodb

My collection has array "name" with objects inside. I need to remove only those objects inside array where "name.x" is blank.
"name": [
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b57b",
"name": "abc",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e6"
},
"qty": "1.0",
"Unit": "pound,lbs"
},
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b430",
"name": "xyz",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
},{
"name.x": []
,
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
}
I tried to get all the ids where name.x is blank using python and used $pull to remove objects base on those ids.But the complete array got deleted.How can I remove the objects that meet the condition.
Think MongoDB update with aggregation pipeline meets your requirement especially to deal with the field name with ..
$set - Update the name array field by $filter name.x field is not an empty array.
db.collection.update({},
[
{
$set: {
name: {
$filter: {
input: "$name",
cond: {
$ne: [
{
$getField: {
field: "name.x",
input: "$$this"
}
},
[]
]
}
}
}
}
}
],
{
multi: true
})
Sample Mongo Playground

Why doesn't mongoose aggregate method return all fields of a document?

I have the following document
[
{
"_id": "624713340a3d2901f2f5a9c0",
"username": "fotis",
"exercises": [
{
"_id": "624713530a3d2901f2f5a9c3",
"description": "Sitting",
"duration": 60,
"date": "2022-03-24T00:00:00.000Z"
},
{
"_id": "6247136a0a3d2901f2f5a9c6",
"description": "Coding",
"duration": 999,
"date": "2022-03-31T00:00:00.000Z"
},
{
"_id": "624713a00a3d2901f2f5a9ca",
"description": "Sitting",
"duration": 999,
"date": "2022-03-30T00:00:00.000Z"
}
],
"__v": 3
}
]
And I am executing the following aggregation (on mongoplayground.net)
db.collection.aggregate([
{
$match: {
"_id": "624713340a3d2901f2f5a9c0"
}
},
{
$project: {
exercises: {
$filter: {
input: "$exercises",
as: "exercise",
cond: {
$eq: [
"$$exercise.description",
"Sitting"
]
}
}
},
limit: 1
}
}
])
And the result is the following
[
{
"_id": "624713340a3d2901f2f5a9c0",
"exercises": [
{
"_id": "624713530a3d2901f2f5a9c3",
"date": "2022-03-24T00:00:00.000Z",
"description": "Sitting",
"duration": 60
},
{
"_id": "624713a00a3d2901f2f5a9ca",
"date": "2022-03-30T00:00:00.000Z",
"description": "Sitting",
"duration": 999
}
]
}
]
So my first question is why is the username field not included in the result?
And the second one is why aren't the exercises limited to 1? Is the limit currently applied to the whole user document? If so, is it possible to apply it only on exercises subdocument?
Thank you!
First Question
When you use $project stage, then only the properties that you specified in the stage will be returned. You only specified exercises property, so only that one is returned. NOTE that _id property is returned by default, even you didn't specify it.
Second Question
$limit is also a stage as $project. You can apply $limit to the whole resulting documents array, not to nested array property of one document.
Solution
In $project stage, you can specify username filed as well, so it will also be returned. Instead of $limit, you can use $slice to specify the number of documents that you want to be returned from an array property.
db.collection.aggregate([
{
"$match": {
"_id": "624713340a3d2901f2f5a9c0"
}
},
{
"$project": {
"username": 1,
"exercises": {
"$slice": [
{
"$filter": {
"input": "$exercises",
"as": "exercise",
"cond": {
"$eq": [
"$$exercise.description",
"Sitting"
]
}
}
},
1
]
}
}
}
])
Working example

MongoDB Aggregation - Filter array with another array

{
"_id": {
"$oid": "5f8f067ecf44854d4c3b5286"
},
"photo": "",
"followers": [
{
"$oid": "5f8f26f8cf44854d4c3b528f"
},
{
"$oid": "5f9f1984cf44854d4c3b5292"
},
{
"$oid": "5f8f06c9cf44854d4c3b528e"
},
{
"$oid": "604b1d0649a2052e912f9c3f"
},
{
"$oid": "5f8f0688cf44854d4c3b5287"
},
{
"$oid": "62371c3b8fabe53cf4386b1f"
}
],
"following": [
{
"$oid": "5f9f1984cf44854d4c3b5292"
},
{
"$oid": "5f8f26f8cf44854d4c3b528f"
},
{
"$oid": "5f8f06c9cf44854d4c3b528e"
}
],
"email": "johndoe#test.com",
"firstname": "John",
"lastname": "Doe",
"username": "JohnDoe01",
"__v": 0
}
I am trying to get a list of followers from a specific user. I have a list of blocked users, so I need to exclude those users from the followers list.
For eg:
let blockedUsers = ['5f8f26f8cf44854d4c3b528f', '5f9f1984cf44854d4c3b5292'];
FYI : followers also user objects
Let me know any further details needed. Thanks in advance.
You can use $filter to filter the follower (id) that is not in the blocked list.
While you perform the comparison, make sure:
Option 1: Value(s) in the blocked list cast to ObjectId
or
Option 2: Cast the follower to string
Must compare values with the same type.
db.collection.aggregate({
$set: {
followers: {
$filter: {
input: "$followers",
cond: {
$not: {
$in: [
{
$toString: "$$this" // Or "$$this._id" for user Object
},
[
"5f8f26f8cf44854d4c3b528f",
"5f9f1984cf44854d4c3b5292"
]
]
}
}
}
}
}
})
Sample Mongo Playground

How to create an array containing arrays on MongoDB

I'm trying to make a query to mongodb. I want to get an array containing [location, status] of every document.
This is how my collection looks like
{
"_id": 1,
"status": "OPEN",
"location": "Costa Rica",
"type": "virtual store"
},
{
"_id": 2,
"status": "CLOSED",
"location": "El Salvador"
"type": "virtual store"
},
{
"_id": 3,
"status": "OPEN",
"location": "Mexico",
"type": "physical store"
},
{
"_id": 4,
"status": "CLOSED",
"location": "Nicaragua",
"type": "physical store"
}
I made a query, using the aggregate framework, trying to get all documents that match that specific type of store.
{
{'$match': {
'type': { '$eq': "physical store"}
}
}
What I want is something like this:
{
{
'stores': [
["Mexico", "OPEN"],
["Nicaragua", "CLOSED"]
]
},
}
I tried with the $push but couldn't make it.
Could someone please guide me on how to do it.
Since { $push: ["$location", "$status"] } would give you the error The $push accumulator is a unary operator. You would have to work around it a bit by passing to it a single object that output your desired array. One way to do it would be:
[
{
"$match": {
"type": {
"$eq": "physical store"
}
}
},
{
"$group": {
"_id": null,
"stores": {
"$push": {
"$slice": [["$location", "$status"], 2]
}
}
}
}
]
If the given documents are not sub-documents, then below is the approach:
db.collection.find({
type: {
$eq: "physical store"
}
},
{
location: 1,
status: 1
})
MongoPlayGround link for the above
If, they are the part of a field (means they are sub-documents), then below is the approach:
db.collection.aggregate([
{
$project: {
stores: {
$filter: {
input: "$stores",
as: "store",
cond: {
$eq: [
"$$store.type",
"physical store"
]
}
}
}
}
},
{
$unwind: "$stores"
},
{
$project: {
location: "$stores.location",
status: "$stores.status",
_id: "$stores._id"
}
}
])
MongoPlayGround link for the above