mongodb - extract a particular value in an embedded array within an array - arrays

I'm fairly new to mongoDB, but I've managed to archive a load of documents into a new collection called documents_archived in the following format using an aggregation pipeleine:
{
"_id" : ObjectId("5a0046ef2039404645a42f52"),
"archive" : [
{
"_id" : ObjectId("54e60f49e4b097cc823afe8c"),
"_class" : "xxxxxxxxxxxxx",
"fields" : [
{
"key" : "Agreement Number",
"value" : "1002465507"
}
{
"key" : "Name",
"value" : "xxxxxxxx"
}
{
"key" : "Reg No",
"value" : "xxxxxxx"
}
{
"key" : "Surname",
"value" : "xxxxxxxx"
}
{
"key" : "Workflow Id",
"value" : "xxxxxxxx"
}
],
"fileName" : "Audit_C1002465507.txt",
"type" : "Workflow Audit",
"fileSize" : NumberLong(404),
"document" : BinData(0, "xxxxx"),
"creationDate" : ISODate("2009-09-25T00:00:00.000+0000"),
"lastModificationDate" : ISODate("2015-02-19T16:28:57.016+0000"),
"expiryDate" : ISODate("2018-09-25T00:00:00.000+0000")
}
]
}
Now, I'm trying to extract just the Agreement Number's value. However, I have tried many things that my limited knowledge, searching and documentation will allow. Wondered if the mongoDB experts out there can help. Thank you.

Here's a solution that uses the agg framework. I am assuming that each doc can have more than one entry in the archive field but only one Agreement Number in the fields array because your design appears to be key/value. If multiple Agreement Numbers show up in the fields array we'll have to add an additional $unwind but for the moment, this should work:
db.foo.aggregate([
{$unwind: "$archive"}
,{$project: {x: {$filter: {
input: "$archive.fields",
as: "z",
cond: {$eq: [ "$$z.key", "Agreement Number" ]}
}}
}}
,{$project: {_id:false, val: {$arrayElemAt: ["$x.value",0]} }}
]);
{ "val" : "1002465507" }

You can use following in mongo shell to extract only values:
db.documents_archived.find().forEach(function(doc) {
doc.archive[0].fields.forEach(function(field) {
if (field.key == "Agreement Number") {
print(field.value)
}
})
})

Related

Compare array within objects in an array of the same Mongo document

I have a Mongo database with multiple documents and they all contain 2 Items for in store and online locations. The difference will be that attributes within the items object may differ. I am trying to capture all documents that have differing attributes between the object items with the array.
I've tried using $expr and comparing the position of the elements such as "Items.0.Attributes" == "Items.1.Attributes" but had no luck.
{
"ID" : "123456789",
"Items" : [
{
"ItemDept" : "softLines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts"
},
"Attributes" : [ "blue","small","mens"],
"Season" : "Summer"
"Location":"online"
}
,
{
"ItemDept" : "softlines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts")
},
"Attributes" : [ "blue","small","women"],
"Season" : "Summer"
"Location":"stores"
}
]
}
If I understand what you want to find/output, here's one way you could do it.
db.collection.find({
"$expr": {
"$not": {
"$setEquals": [
{"$first": "$Items.Attributes"},
{"$last": "$Items.Attributes"}
]
}
}
})
Try it on mongoplayground.net.

How to group records based on array elements using MongoDB

I have a data collection which contains a set of records in the following format.
{
"_id" : 22,
"title" : "3D User Interfaces with Java 3D",
"isbn" : "1884777902",
"pageCount" : 520,
"publishedDate" : ISODate("2000-08-01T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/barrilleaux.jpg",
"longDescription" : "Description",
"status" : "PUBLISH",
"authors" : [
"Jon Barrilleaux"
],
"categories" : [
"Java",
"Computer Graphics"
]
},
{
"_id" : 23,
"title" : "Specification by Example",
"isbn" : "1617290084",
"pageCount" : 0,
"publishedDate" : ISODate("2011-06-03T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
"status" : "PUBLISH",
"authors" : [
"Gojko Adzic"
],
"categories" : [
"Software Engineering"
]
}
Please note that the 'categories' is an array.
I want to count the published books for each category. I tried the following solution, but it treated the entire array as one group.
db.books.aggregate([
{
$group:{_id:"$categories", total:{$sum:1}}
}
])
Instead of so, I want to count the number of records for each individual category value inside 'categories' array.
You should first use $unwind which outputs one document for each element in the array.
db.books.aggregate([
{
$unwind : "$categories"
},
{
$group : { _id : "$categories", total: { $sum: 1 } }
}
])

MongoDB query to retrieve a specific value from the document located in a array

I am trying to make a request in a document with mongodb.
In this document
{
"_id" : ObjectId("5bd19a92da24674fdabd26b6"),
"search" : "try",
"name" : "try",
"email" : "yes#gmail.com",
"password" : "$2a$10$YIRuApqDy/L8HU7R1k2SB.aC2hqH8xFDbl3/muF7PsoN6/SGzsH4q",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 45587899,
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
],
"groupes" : [ ]
}
I'm looking to get just the id in friend, not all of the document just 1 id in friend with where i try this :
db.users.find({$and:[{"friend.id":"ObjectId(5bcee588ae409f434d35c76c)"},{"search":"try"}]})
It's not working i got no result.
Thank you for helping me.
I am not 100% sure I do understand your question properly. You should be able to query the described document via the following query:
find(
/* query by 'search' and the specific friend-id */
{'friend.id': ObjectId("5bcee588ae409f434d35c76c"), search: 'try'},
/* return only that 'friend' element which matches the queried 'friend-id' */
{_id:0, friend:{$elemMatch:{id:ObjectId("5bcee588ae409f434d35c76c")}}}
)
You get the following result:
{
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
]
}
db.users.find({
friend: {
$elemMatch: {
id: ObjectId("5bcee588ae409f434d35c76c")
}
},
search: 'try'
})

MongoDB - Pull multiple objects from an array

Hi I'm trying to remove multiple objects from an array that looks like this.
{
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b3"),
"owner" : "1",
"group_name" : "PAASCU Board",
"group_members" : [
{
"faculty_name" : "Cheska Dela Rosa",
"faculty_number" : 2,
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b5")
},
{
"faculty_name" : "Earl Sempio",
"faculty_number" : 7323,
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b4")
},
{
"faculty_number" : 203,
"faculty_name" : "Sample",
"_id" : ObjectId("5a7dbf7952bd150a94d83958")
},
{
"faculty_number" : 8025,
"faculty_name" : "Sample Postman",
"_id" : ObjectId("5a7dc64a1cf5dd3d50167d53")
}
],
"__v" : 0 }
It works when I remove a single object using the $pull with this code.
db.getCollection('groups').update({_id: ObjectId("5a7da1bda21d5f3e8cf005b3")}, {$pull: {"group_members": {"faculty_number":8025}}})
But what if I want to remove multiple objects with different faculty_number? I tried using the $each method just like how I add multiple objects in the array but it doesn't work well.
Use $in operator to pass the list of faculty values to remove documents from embedded array. More here
Try
db.groups.update(
{"_id": ObjectId("5a7da1bda21d5f3e8cf005b3")},
{"$pull":{"group_members":{"faculty_number":{$in:[8025,7323]}}}}
)

Mongoose Query: Find an element inside an array

Mongoose/Mongo noob here:
My Data
Here is my simplified data, each user has his own document
{ "__v" : 1,
"_id" : ObjectId( "53440e94c02b3cae81eb0065" ),
"email" : "test#test.com",
"firstName" : "testFirstName",
"inventories" : [
{ "_id" : "active",
"tags" : [
"inventory",
"active",
"vehicles" ],
"title" : "activeInventory",
"vehicles" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0069" ),
"tags" : [
"vehicle" ],
"details" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0066" ),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms" } ] } ] },
{ "title" : "soldInventory",
"_id" : "sold",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] },
{ "title" : "deletedInventory",
"_id" : "deleted",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] } ] }
As you can see, each user has an inventories property that is an array that contains 3 inventories (activeInventory, soldInventory and deletedInventory)
My Query
Given an user's email a a vehicle ID, i would like my query to go through find the user's activeInventory and return just the vehicle that matches the ID. Here is what I have so far:
user = api.mongodb.userModel;
ObjectId = require('mongoose').Types.ObjectId;
return user
.findOne({email : params.username})
.select('inventories')
.find({'title': 'activeInventory'})
//also tried
//.where('title')
//.equals('activeInventory')
.exec(function(err, result){
console.log(err);
console.log(result);
});
With this, result comes out as an empty array. I've also tried .find('inventories.title': 'activeInventory') which strangely returns the entire inventories array. If possible, I'd like to keep the chaining query format as I find it much more readable.
My Ideal Query
return user
.findOne({email : params.username})
.select('inventories')
.where('title')
.equals('activeInventory')
.select('vehicles')
.id(vehicleID)
.exec(cb)
Obviously it does not work but it can give you an idea what I'm trying to do.
Using the $ positional operator, you can get the results. However, if you have multiple elements in the vehicles array all of them will be returned in the result, as you can only use one positional operator in the projection and you are working with 2 arrays (one inside another).
I would suggest you take a look at the aggregation framework, as you'll get a lot more flexibility. Here's an example query for your question that runs in the shell. I'm not familiar with mongoose, but I guess this will still help you and you'd be able to translate it:
db.collection.aggregate([
// Get only the documents where "email" equals "test#test.com" -- REPLACE with params.username
{"$match" : {email : "test#test.com"}},
// Unwind the "inventories" array
{"$unwind" : "$inventories"},
// Get only elements where "inventories.title" equals "activeInventory"
{"$match" : {"inventories.title":"activeInventory"}},
// Unwind the "vehicles" array
{"$unwind" : "$inventories.vehicles"},
// Filter by vehicle ID -- REPLACE with vehicleID
{"$match" : {"inventories.vehicles._id":ObjectId("53440e94c02b3cae81eb0069")}},
// Tidy up the output
{"$project" : {_id:0, vehicle:"$inventories.vehicles"}}
])
This is the output you'll get:
{
"result" : [
{
"vehicle" : {
"_id" : ObjectId("53440e94c02b3cae81eb0069"),
"tags" : [
"vehicle"
],
"details" : [
{
"_id" : ObjectId("53440e94c02b3cae81eb0066"),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms"
}
]
}
}
],
"ok" : 1
}
getting the chaining query format ... i dont know how to parse it but, what you are searching for is projection, you should take a look to http://docs.mongodb.org/manual/reference/operator/projection/
it would probably look like this :
user.findOne({email: params.username}, {'inventories.title': {$elemMatch: "activeInventory", 'invertories.vehicle.id': $elemMatch: params.vehicleId}, function(err, result) {
console.log(err);
console.log(result);
})

Resources