MongoDB returning two array while using alias - mongodb

I am a json in mongodb. The structure is below --
{
id: "1",
name: "sample",
user: [
{
data_alias: "ex",
value: "efg"
}
]
}
Now I want the the data_alias to be data after mongodb returns the result.
When I am using below query --
db.coll.find(
{"id":"1"},
{"data": "$user.data_alias","_id": 0,"value":1}
)
Now it is retuning data like --
{
"user": [
{
"value": "efg",
},
],
"data": [
"ex"
]
}
But I want the returning value should be like --
{
"data": "ex",
"name": "sample"
}
Also I have tried with aggregate function
db.colls.aggregate([
{
$match: {
"id": "1"
}
},
{
"$project": {
"_id": 0,
"data": "$user.data_alias"
}
}
]);
Both the queries returning same result.

Just $unwind the user array and $project to your expected output.
db.collection.aggregate([
{
$match: {
name: "sample"
}
},
{
"$unwind": "$user"
},
{
"$project": {
_id: 0,
"name": 1,
"data": "$user.data_alias"
}
}
])
Here is the Mongo playground for your reference.

Related

MongoDB Aggregate Query to find the documents with missing values

I am having a huge collection of objects where the data is stored for different employees.
{
"employee": "Joe",
"areAllAttributesMatched": false,
"characteristics": [
{
"step": "A",
"name": "house",
"score": "1"
},
{
"step": "B",
"name": "car"
},
{
"step": "C",
"name": "job",
"score": "3"
}
]
}
There are cases where the score for an object is completely missing and I want to find out all these details from the database.
In order to do this, I have written the following query, but seems I am going wrong somewhere due to which it is not displaying the output.
I want the data in the following format for this query, so that it is easy to find out which employee is missing the score for which step and which name.
db.collection.aggregate([
{
"$unwind": "$characteristics"
},
{
"$match": {
"characteristics.score": {
"$exists": false
}
}
},
{
"$project": {
"employee": 1,
"name": "$characteristics.name",
"step": "$characteristics.step",
_id: 0
}
}
])
You need to use $exists to check the existence
playground
You can use $ifNull to handle both cases of 1. the score field is missing 2. score is null.
db.collection.aggregate([
{
"$unwind": "$characteristics"
},
{
"$match": {
$expr: {
$eq: [
{
"$ifNull": [
"$characteristics.score",
null
]
},
null
]
}
}
},
{
"$group": {
_id: null,
documents: {
$push: {
"employee": "$employee",
"name": "$characteristics.name",
"step": "$characteristics.step",
}
}
}
},
{
$project: {
_id: false
}
}
])
Here is the Mongo playground for your reference.

count based on nested key mongodb

How can i count based on xTag key is on doc
I tried this but it does not provide me actual count
db.collection.find({
"products.xTag": {
$exists: false
}
}).count();
when you run with $exist:true i would expect result 1
When you run with $exist:false i would expect result 3
Playground: https://mongoplayground.net/p/_gf7RzGc8oB
Structure:
[
{
"item": 1,
"products": [
{
"name": "xyz",
"xTag": 32423
},
{
"name": "abc"
}
]
},
{
"item": 2,
"products": [
{
"name": "bob",
},
{
"name": "foo"
}
]
}
]
It is not possible with find(), You can use aggregate(),
$unwind deconstruct products array
$match your condition
$count total documents
db.collection.aggregate([
{ $unwind: "$products" },
{ $match: { "products.xTag": { $exists: false } } },
{ $count: "count" }
])
Playground

Sort records by array field values in MongoDb

I have a collection which has documents like;
{
"name": "Subject1",
"attributes": [{
"_id": "security_level1",
"level": {
"value": "100",
"valueKey": "ABC"
}
}, {
"_id": "security_score1",
"level": {
"value": "1000",
"valueKey": "CDE"
}
}
]
},
{
"name": "Subject2",
"attributes": [{
"_id": "security_level1",
"level": {
"value": "99",
"valueKey": "XYZ"
}
}, {
"_id": "security_score1",
"level": {
"value": "2000",
"valueKey": "EDF"
}
}
]
},
......
Each document will have so many attributes generated dynamically, can be different in size.
Is it possible to sort records based on level.value of security_level1? (security_level1 is _id field value)
As per above example, the second document ("name": "Subject2") should come first as the value ('level.value') of _id:security_level1 is 99, which is less than of Subject1's security_level1 value (100) - (Ascending order)
Use $filter and $arrayElemAt to get security_level1 item. Then you can use $toInt to convert that value to an integer so that $sort can be applied:
db.collection.aggregate([
{
$addFields: {
level: {
$let: {
vars: {
level_1: { $arrayElemAt: [ { $filter: { input: "$attributes", cond: { $eq: [ "$$this._id", "security_level1" ] } } } ,0] }
},
in: {
$toInt: "$$level_1.level.value"
}
}
}
}
},
{
$sort: {
level: 1
}
}
])
Mongo Playground

Spring mongo: Query Subdocument array to get matching subdocuments using IN clause

Hi have a collection as below:
clientPref
{
clntId: 1234,
clntType: "internal",
status: "PROCESSED",
prefs: [
{
name: "AAA",
value: "value1"
},
{
name: "BBB",
value: "value2"
},
{
name: "CCC",
value: "value3"
}
]
}
If I find by prefs.name $in ("AAA", "CCC"), I'm getting all the subdocuments along with the parent.
I then tried using prefs.$: 1 in the fields parameter of #Query but then it's returning the first matching subdocument only.
Desired output
{
clntId: 1234,
clntType: "internal",
status: "PROCESSED",
prefs: [
{
name: "AAA",
value: "value1"
},
{
name: "CCC",
value: "value3"
}
]
}
Is there a way I can get AAA and CCC subdocument by using #Query annotation. If not then how to do it using aggregation? Still pretty new to mongo so not able to figure out a way to get desired result.
You need to project what is needed.
{
"prefs.$":1,
"clntType":1,
"status":1
}
play
Query:
db.collection.find({
"prefs.name": "AAA"
},
{
"prefs.$": 1,
"clntType": 1,
"status": 1
})
Output:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"clntType": "internal",
"prefs": [
{
"name": "AAA",
"value": "value1"
}
],
"status": "PROCESSED"
}
]
To get all sub doc:
Play
db.collection.aggregate([
{
"$unwind": "$prefs"
},
{
"$match": {
"prefs.name": {
"$in": [
"AAA",
"CCC"
]
}
}
}
])
If you want to group all the data again, you can do play
db.collection.aggregate([
{
"$unwind": "$prefs"
},
{
"$match": {
"prefs.name": {
"$in": [
"AAA",
"CCC"
]
}
}
},
{
"$group": {
"_id": "$_id",
"data": {
"$push": "$$ROOT"
}
}
}
])

Fetch mongo documents based on multiple fields

Given mongo document of the following form in a collection:
{
"_id":"ObjectId",
"value":{
"id": 1,
"payment": [
{
"status": {
"id": "1.1",
"value": "Paid"
}
},
{
"status": {
"id": "1.2",
"value": "Scheduled"
}
},
{
"status": {
"id": "1.3",
"value": "Recorded"
}
}
]
}
}
ids = [1,2,3,4]
How can i fetch all documents having id in ids and at least one of payments.status.value equal to Scheduled state ?
I am using the following query but it's returning 0 records,
db.collectionName.find({$and:[{"value.id":{$in:ids}},{"value.payment.status.value":"Scheduled"}]})`
you can specify the name of the collection
so instead of this:
db.collection.find({
$and:
[
{"value.id": {$in:ids}},
{"value.payment.status.value":"Scheduled"}
]
})
you can write:
db.payments.find({
$and:
[
{"value.id":{$in:ids}},
{"value.payment.status.value":"Scheduled"}
]
})
db.collection.find({
'value.payment': {
$elemMatch: {
'status.value': 'Scheduled'
}
},
'value.id': {
$in: [1, 2, 3, 4]
}
}, {
'value.id': 1,
'value.payment.$.status': 1
})