MongoDB $elemMatch display issue - mongodb

Listed are the following sample documents in a test collection
My requirement is to extract *only" two fields
"host.name" and "host.config.storageDevice.scsiLun.lunType" matching the condition that "host.config.storageDevice.scsiLun.lunType" : "cdrom1" and "host.name" : "on-xxx"
Like I mentioned above , I only want attribute "lunType" to be displayed in the array and not "a" or "b"
I attempted to use both $elemMatch and $projection and it always seems to return all the attributes of array "lunType" ... Am I missing anything here
Attempted in reference to documentation
http://docs.mongodb.org/manual/reference/projection/elemMatch/
Query
db.test.find({"host.config.storageDevice.scsiLun": { $elemMatch: { "lunType" : "cdrom1" } } },{ "host.name" : 1, "host.config.storageDevice.scsiLun.$" : 1})
db.test.find({"host.config.storageDevice.scsiLun.lunType" : "cdrom1" },{ "host.name" : 1, "host.config.storageDevice.scsiLun.$" : 1})
Documents in collection
{
"_id" : ObjectId("51d57f3ad4ebc6c87962d4c0"),
"host" : {
"name" : "on-xxx",
"config" : {
"storageDevice" : {
"scsiLun" : [
{
"a" : "1",
"lunType" : "cdrom1"
},
{
"a" : "2",
"lunType" : "disk2"
},
{
"a" : "3",
"lunType" : "disk3"
}
]
}
}
}
}
,
{
"_id" : ObjectId("51d57f59d4ebc6c87962d4c1"),
"host" : {
"name" : "on-yyy",
"config" : {
"storageDevice" : {
"scsiLun" : [
{
"a" : "4",
"lunType" : "cdrom4"
},
{
"a" : "5",
"lunType" : "disk5"
},
{
"a" : "6",
"lunType" : "disk6"
}
]
}
}
}
}
,
{
"_id" : ObjectId("51d57f74d4ebc6c87962d4c2"),
"host" : {
"name" : "on-zzz",
"config" : {
"storageDevice" : {
"scsiLun" : [
{
"a" : "7",
"lunType" : "cdrom11"
},
{
"a" : "8",
"lunType" : "disk22"
},
{
"a" : "9",
"lunType" : "disk32"
}
]
}
}
}
}

All $elemMatch does is to return the first element of the array that matches a criteria, but it will give you the entire element, that is both "a" and "lunType" properties.
What might get the desired result with aggregation using $unwind to break down the array, then $match to filter and $project to show only the "lunType" field.
I didn't test the query but it should look like this:
db.test.aggregate(
{ $unwind : "$host.config.storageDevice.scsiLun" },
{ $match : { host.name : "on-xxx" ,
host.config.storageDevice.scsiLun.lunType : "cdrom1" } },
{ $project : {
_id : 0 ,
host.config.storageDevice.scsiLun.lunType : 1 }
);

Related

Find from another find in mongodb

In Mysql I can do a Select from another Select.
So I would ask if I can do the same in Mongodb.
For more explanation, I need to retreive the transaction of the a specific userOwner with just the last dateTransaction in the history object of this collection.So if this userOwner isn't in the last history we shoudn't retreive this transaction.
I used at first this query:
#Query(value = "{'history':{'$elemMatch':{'userOwner': ?0}}}")
but it returns all the elements even those where this userOwner isn't with the last "dateTransaction".
So I aim to de a query that it returns for each transaction just the last dateTransaction with userOwner of the "history" array :
.find({},{dateTransaction: {$slice: 1} }).limit(1)
and after do another query from this one.
Anyone has an idea or examples.
Tnx
This is my Collection called "piece":
{
"_id" : ObjectId("1"),
"history" : [{
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-30T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-23T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("2"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("3"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}
As example the result for the userOwner 2 should be :
{
"_id" : ObjectId("2"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("3"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}
it looks like your data is stored in one collection - so this is a kind of bad design as it needs more overhead to work with....
below aggregation query which has a lookup to the same collection to match data for user:2
var unwind = {
$unwind : "$history"
}
var matchUser = {
$match : {
"history.userOwner" : "2"
}
}
var lookUp = {
$lookup : {
from : "shm",
localField : "userOwner",
foreignField : "userOwner",
as : "t"
}
}
var unwindTransactions = {
$unwind : "$t"
}
var unwindTransactions2 = {
$unwind : "$t.transactions"
}
var match2 = {
$match : {
"t.transactions.userOwner" : "2"
}
}
var project = {
$project : {
_id : 0,
recordId : "$_id",
transactionId : "$t._id",
dateOfTransaction : "$history.dateTransaction",
userOwner : "$history.userOwner",
}
}
db.shm.aggregate([unwind,
matchUser,
lookUp,
unwindTransactions,
unwindTransactions2,
match2,
project
])
and as a result we have two records of user transactions
{
"recordId" : ObjectId("575e7e8b852cb76369c9e446"),
"transactionId" : ObjectId("575e7e8b852cb76369c9e447"),
"dateOfTransaction" : ISODate("2016-05-23T00:00:00.000Z"),
"userOwner" : "2"
},{
"recordId" : ObjectId("575e7e8b852cb76369c9e446"),
"transactionId" : ObjectId("575e7e8b852cb76369c9e448"),
"dateOfTransaction" : ISODate("2016-05-23T00:00:00.000Z"),
"userOwner" : "2"
}
Please consider split of that collection as in current form will give you a lot of headache when processing more complex queries

Sorting objects in array within mongodb

I've seen this question all over google/SO/mongo docs, and I've tried to implement the solution, but it's not working for me. I have the following test database:
> db.test.find().pretty()
{
"_id" : ObjectId("56b4ab167db9acd913ce6e07"),
"state" : "HelloWorld",
"items" : [
{
"guid" : "123"
},
{
"guid" : "124"
},
{
"guid" : "123"
}
]
}
And I want to sort by the "guid" element of items. Running the sort commands yields:
> db.test.find().sort( {"items.guid" : 1}).pretty()
{
"_id" : ObjectId("56b4ab167db9acd913ce6e07"),
"state" : "HelloWorld",
"items" : [
{
"guid" : "123"
},
{
"guid" : "124"
},
{
"guid" : "123"
}
]
}
How can I sort by the "guid" element, so that the returned output of "items" is the 123, 123, and 124 guids (essentially move the child elements of "items" so that they're sorted by "guid")?
EDIT: I've also tried to use the $orderby command, doesn't accomplish what I want:
> db.test.find({ $query : {}, $orderby: {'items.guid' : 1} }).pretty()
{
"_id" : ObjectId("56b4ab167db9acd913ce6e07"),
"state" : "HelloWorld",
"items" : [
{
"guid" : "123"
},
{
"guid" : "124"
},
{
"guid" : "123"
}
]
}
Here is how it can be done using aggregate
db.test.aggregate([
{
$unwind : '$items'
},
{
$sort : {'items.guid' : 1}
},
{
$group : {
_id : '$_id',
state : {$first : '$state'},
items : {
$push : {'guid' : '$items.guid'}
}
}
}
]).pretty()
This is the output from this command.
{
"_id" : ObjectId("56b4ab167db9acd913ce6e07"),
"state" : "HelloWorld",
"items" : [
{
"guid" : "123"
},
{
"guid" : "123"
},
{
"guid" : "124"
}
]
}

how to get this query in mongoDB

I have this collection...
> db.banks.find().pretty()
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f4"),
"name" : "A",
"branches" : [
{
"branch_id" : 8561,
"name" : "X",
},
{
"branch_id" : 8576,
"name" : "Y",
}
]
}
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f5"),
"name" : "B",
"branches" : [
{
"branch_id" : 3238,
"name" : "Z",
}
]
}
with this command :
db.banks.aggregate({$project{"branches.name":1,"_id":0}});
get this result :
{ "branches" : { { "name" : "X" }, { "name" : "Y" } } }
{ "branches" : { { "name" : "Z" } } }
but; how I get this result?
(In fact, one object and without "branches".)
{{"name" : "X"}, {"name" : "Y"}, {"name" : "Z"}}
very thanks...
One way you could go about this is to do an $unwind first in the aggregation pipeline to get a deconstructed array with a document for each element and then group by the array element $branches.name:
db.banks.aggregate([
{ $unwind: '$branches'},
{
$group: {
_id: {
name: '$branches.name'
}
}
},
{
$project: {
_id: 0,
name: '$_id.name'
}
},
{ $sort : { "name" : 1 } }
])
Outputs:
{
"result" : [
{
"name" : "X"
},
{
"name" : "Y"
},
{
"name" : "Z"
}
],
"ok" : 1
}

MongodDB retrieve a subdocument by the property name

My document looks like:
{ "entity_id" : 2,
"features" :
[
{ "10" : "name" },
{ "20" : "description" },
... ,
{ "90" : "availability" }
]
}
I would like to, knowing 2 things: the value of "entity_id" (2), and the value of the property in one of the elements of the "features" array, to retrieve only the subdocument
{ "20" : "description" }
in one query. Many thanks!
If you want to get only a part of the whole document, use so called Projection operators
See examples below:
> db.collection.find().pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"entity_id" : 2,
"features" : [
{
"10" : "name"
},
{
"20" : "description"
},
{
"90" : "availability"
}
]
}
Projection operators are specified in find() like here:
> db.collection.find({},{ features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"features" : [
{
"20" : "description"
}
]
}
> db.collection.find({},{ entity_id : 1, features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"entity_id" : 2,
"features" : [
{
"20" : "description"
}
]
}
> db.collection.find({},{ _id : 0, entity_id : 1, features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{ "entity_id" : 2, "features" : [ { "20" : "description" } ] }
$elemMatch for projection is available in MongoDB since version 2.2.
Hope it solves your problem.

In MongoDb, how to apply sort internal fields present in document?

My document looks like this
{
field1: somevalue,
name:xtz
nested_documents: [ // array of nested document
{ x:"1", y:"2" }, // first nested document
{ x:"2", y:"3" }, // second nested document
{ x:"-1", y:"3" }, // second nested document
// ...many more nested documents
]
}
How one can sort the data present in nested_documents?
Expected answer is shown below:
nested_documents: [ { x:"-1", y:"3" },{ x:"1", y:"2" },{ x:"2", y:"3" }]
To do this you would have to use the aggregation framework
db.test.aggregate([{$unwind:'$nested_documents'},{$sort:{'nested_documents.x':
1}}])
this returns
"result" : [
{
"_id" : ObjectId("5139ba3dcd4e11c83f4cea12"),
"field1" : "somevalue",
"name" : "xtz",
"nested_documents" : {
"x" : "-1",
"y" : "3"
}
},
{
"_id" : ObjectId("5139ba3dcd4e11c83f4cea12"),
"field1" : "somevalue",
"name" : "xtz",
"nested_documents" : {
"x" : "1",
"y" : "2"
}
},
{
"_id" : ObjectId("5139ba3dcd4e11c83f4cea12"),
"field1" : "somevalue",
"name" : "xtz",
"nested_documents" : {
"x" : "2",
"y" : "3"
}
}
],
"ok" : 1
Hope this helps