I have an aggregate query which correctly "marks" the matched documents but returns all the documents on the collection. How do I return only the matched documents?
Here's my query:
db.trainers.aggregate([
{ $addFields: { returnObject: { $regexFind: { input: "$username", regex: /master/ } } } },
]);
// 1
{
"_id": ObjectId("5fe1c555607a0d05492dc481"),
"email": "PraXXXes0#gmail.com",
"username": "816XXX063",
"created": ISODate("2020-12-22T10:07:17.172Z"),
"returnObject": null,
}
// 2
{
"_id": ObjectId("5fe046caddfee639193a4880"),
"email": "HobbiXXXXious#gmail.com ",
"username": "PoXXXXmaster75785",
"created": ISODate("2020-12-21T06:55:06.262Z"),
"returnObject": {
"match": "master",
"idx": NumberInt("4"),
"captures": [ ]
},
}
I do not want those returnObject nulls...
Thanks
Related
I am trying to select document with filter userInteractions array. I need to remove item where userdId = "633eb753c8e3d3fd71d1c254" and return document as result. It is easy way to approach it with MongoDB query?
https://mongoplayground.net/p/2UHw52QJkYu
Example of JSON document:
{
"_id": {
"$oid": "633c25965034208db76cfb1e"
},
"email": "test#test.com",
"users": [
{
"type": "person",
"isActive": true,
"userInteractions": [
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c254"
},
"firstName": "Tom",
"lastName": "Hawkins",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c222"
},
"firstName": "Melan",
"lastName": "Key",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c259"
},
"firstName": "Ken",
"lastName": "Olibar",
},
]
}
]
}
Expecting output:
{
"_id": {
"$oid": "633c25965034208db76cfb1e"
},
"email": "test#test.com",
"users": [
{
"type": "person",
"isActive": true,
"userInteractions": [
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c222"
},
"firstName": "Melan",
"lastName": "Key",
},
{
"userId": {
"$oid": "633eb753c8e3d3fd71d1c259"
},
"firstName": "Ken",
"lastName": "Olibar",
},
]
}
]
}
$set - Set users field.
1.1. $map - Iterate the users array and return a new array.
1.1.1. $mergeObjects - Merge the current iterated document and the document from the result 1.1.1.1.
1.1.1.1. $filter - Filter the document(s) from the userInteractions array from the current iterated document.
db.collection.aggregate([
{
$set: {
users: {
$map: {
input: "$users",
as: "user",
in: {
$mergeObjects: [
"$$user",
{
userInteractions: {
$filter: {
input: "$$user.userInteractions",
cond: {
$ne: [
"$$this.userId",
{
$toObjectId: "633eb753c8e3d3fd71d1c254"
}
]
}
}
}
}
]
}
}
}
}
}
])
Demo # Mongo Playground
{
"id": "1234",
"applicant": [
{
"phone": [
{
"prirotynumber": "1",
"areacode": "407",
"linenumber": "1234",
"exchangenumber": "7899"
},
{
"prirotynumber": "27",
"areacode": "407",
"linenumber": "1234",
"exchangenumber": "79999"
}
]
}
]
}
for this id=1234 i need to fetch homephonenuber as applicant.phone.areacode+applicant.phone+linenumber+ applicant.phone+exchangenumber if prirotynumber=1
and
cellphone as applicant.phone.areacode+applicant.phone+linenumber+ applicant.phone+exchangenumber if prirotynumber=27
Expected result here:
{
"key":"value"
}
If this isn't what you need, make your expected result more clarify with right sample data.
db.collection.aggregate([
{
"$match": {
"id": "1234",
"applicant.phone.prirotynumber": "1"
}
},
{
"$unwind": "$applicant"
},
{
"$unwind": "$applicant.phone"
},
{
"$match": {
"applicant.phone.prirotynumber": "1"
}
},
{
"$set": {
"homePhoneNumber ": {
$concat: [
"$applicant.phone.areacode",
"-",
"$applicant.phone.linenumber",
"-",
"$applicant.phone.exchangenumber"
]
}
}
}
])
mongoplayground
I have my data saved in mongo db like this
{
"_id": "5eff4376e036e45de9dbc6df",
"social_connections":{
"friend":{
"friends":[
{
"_id": "5eff42dee036e45de9dbc6d3",
"user_name": "x",
"name": "Viper King"
},
{
"_id": "5eff40efe036e45de9dbc6c9",
"user_name": "z",
"name": "Brad Prasad Pitt"
},
{
"_id": "5eff50337508da5ff40bf36e",
"user_name": "test",
"name": "Test"
}
]
},
"followers":{
"following":[
{
"_id": "5eff42dee036e45de9dbc6d3",
"user_name": "x",
"name": "Viper King"
},
{
"_id": "5eff40efe036e45de9dbc6c9",
"user_name": "z",
"name": "Brad Prasad Pitt"
},
{
"_id": "5eff50337508da5ff40bf36e",
"user_name": "test",
"name": "Test"
}
]
}
}
}
I want to make a mongo db query in which I would pass the _id of the document that is 5eff4376e036e45de9dbc6df and a regex that is 'Vi', now I want all those array objects whose name contains 'Vi'. My expected output is:-
{
"_id": "5eff4376e036e45de9dbc6df",
"social_connections":{
"friend":{
"friends":[
{
"_id": "5eff42dee036e45de9dbc6d3",
"user_name": "x",
"name": "Viper King"
}
]
},
"followers":{
"following":[
{
"_id": "5eff42dee036e45de9dbc6d3",
"user_name": "x",
"name": "Viper King"
}
]
}
}
}
You can also make a query which only return _id of those whose name contains 'Vi'
You can use $filter to get a new filtered array and $regexMatch to apply your regular expression:
db.collection.aggregate([
{
$project: {
"social_connections.friend.friends": {
$filter: {
input: "$social_connections.friend.friends",
as: "friend",
cond: {
$regexMatch: { input: "$$friend.name", regex: "Vi" }
}
}
},
"social_connections.followers.following": {
$filter: {
input: "$social_connections.followers.following",
as: "follower",
cond: {
$regexMatch: { input: "$$follower.name", regex: "Vi" }
}
}
}
}
}
])
Mongo Playground
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
I am struggling to find some examples of using the mongo aggregation framework to process documents which has an array of items where each item also has an array of other obejects (array containing an array)
In the example document below what I would really like is an example that sums the itemValue in the results array of all cases in the document and accross the collection where the result.decision was 'accepted'and group by the document locationCode
However, even an example that found all documents where the result.decision was 'accepted' to show or that summmed the itemValue for the same would help
Many thanks
{
"_id": "333212",
"data": {
"locationCode": "UK-555-5566",
"mode": "retail",
"caseHandler": "A N Other",
"cases": [{
"caseId": "CSE525666",
"items": [{
"id": "333212-CSE525666-1",
"type": "hardware",
"subType": "print cartridge",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "acme print cartridge",
"quantity": 2,
"weight": "1.5"
},
"result": {
"decision": "rejected",
"decisionDate": "2019-02-02"
},
"isPriority": true
},
{
"id": "333212-CSE525666-2",
"type": "Stationery",
"subType": "other",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "staples box",
"quantity": 3,
"weight": "1.66"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-03",
"itemValue": "23.01"
},
"isPriority": true
}
]
},
{
"caseId": "CSE885655",
"items": [{
"id": "333212-CSE885655-1",
"type": "marine goods",
"subType": "fish food",
"targetDate": "2020-06-04",
"itemDetail": {
"description": "fish bait",
"quantity": 5,
"weight": "0.65"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-02"
},
"isPriority": false
},
{
"id": "333212-CSE885655-4",
"type": "tobacco products",
"subType": "cigarettes",
"deadlineDate": "2020-06-15",
"itemDetail": {
"description": "rolling tobbaco",
"quantity": 42,
"weight": "2.25"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-02-02",
"itemValue": "48.15"
},
"isPriority": true
}
]
}
]
},
"state": "open"
}
You're probably looking for $unwind. It takes an array within a document and creates a separate document for each array member.
{ foos: [1, 2] } -> { foos: 1 }, { foos: 2}
With that you can create a flat document structure and match & group as normal.
db.collection.aggregate([
{
$unwind: "$data.cases"
},
{
$unwind: "$data.cases.items"
},
{
$match: {
"data.cases.items.result.decision": "accepted"
}
},
{
$group: {
_id: "$data.locationCode",
value: {
$sum: {
$toDecimal: "$data.cases.items.result.itemValue"
}
}
}
},
{
$project: {
_id: 0,
locationCode: "$_id",
value: "$value"
}
}
])
https://mongoplayground.net/p/Xr2WfFyPZS3
Alternative solution...
We group by data.locationCode and sum all items with this condition:
cases[*].items[*].result.decision" == "accepted"
db.collection.aggregate([
{
$group: {
_id: "$data.locationCode",
itemValue: {
$sum: {
$reduce: {
input: "$data.cases",
initialValue: 0,
in: {
$sum: {
$concatArrays: [
[ "$$value" ],
{
$map: {
input: {
$filter: {
input: "$$this.items",
as: "f",
cond: {
$eq: [ "$$f.result.decision", "accepted" ]
}
}
},
as: "item",
in: {
$toDouble: {
$ifNull: [ "$$item.result.itemValue", 0 ]
}
}
}
}
]
}
}
}
}
}
}
}
])
MongoPlayground