Spring data mongoDB push operation with multiple fields are not working - mongodb

I have a set of data objects in MongoDB as-
[
{ "status" : "passed", "version" : "124" , "value" : 6 },
{ "status" : "passed", "version" : "123" , "value" : 10 },
{ "status" : "failed", "version" : "123" , "value" : 16 }
]
and i want to get it in a format like -
[
{
version: 124,
"series" :[
{
"name" : "passed",
"value" : 6
}
]
},
{
version: 123,
"series" : [
{
"name" : "passed",
"value" : 10
},
{
"name" : "failed",
"value" : 16
}
]
}
]
how should i write the query?
I wrote query like
I have written a query like:
Aggregation.group("version").push(new BasicDBObject("name","$status").append("value", "$value")).as("series");
using the aggregate query above, I'm getting like:
[
{
version: 124,
"series" :[
{
"name" : null,
"value" : 6
}
]
},
{
version: 123,
"series" : [
{
"name" : null,
"value" : 10
},
{
"name" : null,
"value" : 16
}
]
}
]
It seems that the value of the status is not taken in the object. How can I resolve this?

My Query is like:
db.results.aggregate([{
{
       "$group": {
             "_id": {
                  "status": "$status",
                  "version": "$version",
              },
             "count": {
                  "$sum": 1
              }
            }
        }, {
            $group: {
                _id: "$_id.version",
                "series": {
                    $push: {
                        "status": "$_id.status",
                        "value": "$count"
                    }
                }
            }
        }
    ]);
So I have to add the aggregation query as:
Aggregation.group("version").push(new BasicDBObject("_id", "$_id.status").append("value", "$value")).as("series");

I tried with mongo aggregation. Try in the shell.
I am not familiarised with spring.
db.getCollection('Test1').aggregate([
{
$group:{
_id:"$version",
version:{$first:"$version"},
series:{
$push:{
name:"$status",
value:"$value"
}
}
}
},
{$project:{_id:0}}
])

Related

MongoDb find with nested array

Lets say I have this kind of collection
{
"_id" :"A",
"title" : "TITLE1",
"brand" : [
{
"brand_id" : "B",
"varients" : [
{
"name" : "RED ",
"price" : 5.0
}
]
},
{
"brand_id" : "C",
"varients" : [
{
"name" : "GREEN",
"price" : 5.0
}
]
},
{
"brand_id" : "D",
"varients" : [
{
"name" : "Others",
"price" : 0.0
}
]
}
],
}
I then want to select one and ONLY the nested data of variants. Have tried with the following statement without any success.
db.testing.findOne( {_id: "A", "brand.brand_id" : 'D'} )
Expected output
"varients" : [
{
"name" : "Others",
"price" : 0.0
}
]
Using findOne you can't get the subset or nest content of the document in the response, but yes using aggregation you can get it in a way you want it
Check out this aggregation pipeline:
[
{
'$match': {
'_id': 'A'
}
}, {
'$unwind': {
'path': '$brand'
}
}, {
'$match': {
'brand.brand_id': 'D'
}
}, {
'$project': {
'varients': '$brand.varients',
'_id': 0
}
}
]

How to multiple push to nested array

I have the following object:
{
"_id" : ObjectId("5d7052a3807ab14e286ba5bd"),
"companyBases" : [
{
"vehicles" : [],
"_id" : ObjectId("5d7052a3807ab14e286ba5b0"),
"name" : "Tech Parking 3",
"location" : {
"lng" : 50.01744,
"lat" : 20.033522
},
"country" : ObjectId("5d7052a2807ab14e286ba578"),
"__v" : 0
},
{
"vehicles" : [],
"_id" : ObjectId("5d7052a3807ab14e286ba5af"),
"name" : "Tech Parking 2",
"location" : {
"lng" : 50.036017,
"lat" : 20.086752
},
"country" : ObjectId("5d7052a2807ab14e286ba578"),
"__v" : 0
}
],
"nameOfCompany" : "Transport Tech Service 2 ",
"plan" : {
"name" : "Enterprise",
"vehicles" : 56,
"companyBases" : 10,
"users" : 10,
"price" : 1200
},
"__v" : 0
}
I've tried to do something like this:
db.companies.update(
{
_id: ObjectId("5d7052a3807ab14e286ba5bd")
},
{
$push: {
"companyBases.$[filter1].vehicles": {
"name": "Truck 1",
"combustion": 28
},
"companyBases.$[filter2].vehicles": {
"name": "Truck 2",
"combustion": 28
}
}
},
{
"arrayFilters": [
{
"filter1._id": "5d7052a3807ab14e286ba5b0"
},
{
"filter2._id": "5d7052a3807ab14e286ba5af"
}
]
}
)
But, it doesn't update my nested arrays "vehicles"
It returns me:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
I checked IDs and it's ok. I've created similar question a few days ago but with $set pipeline not $push - How to update in one query, multiple times without sharing to simple queries? , but i was thinking it's possible to rewrite that example to $push.
Issue: In array filters, the _id is matched with string instead of ObjectId
The following query would precisely update the collection:
db.companies.update(
{
_id: ObjectId("5d7052a3807ab14e286ba5bd")
},
{
$push: {
"companyBases.$[filter1].vehicles": {
"name": "Truck 1",
"combustion": 28
},
"companyBases.$[filter2].vehicles": {
"name": "Truck 2",
"combustion": 28
}
}
},
{
"arrayFilters": [{
"filter1._id": ObjectId("5d7052a3807ab14e286ba5b0")
},
{
"filter2._id": ObjectId("5d7052a3807ab14e286ba5af")
}
]
}
)

mongodb find the document by id and then group the result based on name field

I have a collection with multiple documents like
{
"_id" : ObjectId("5a64d076bfd103df081967ae"),
"status" : "",
"Number" : 53,
"values" : [
{
"date" : "2015-05-18",
"value" : 12.41
},
{
"date" : "2015-05-19",
"value" : 12.45
},
],
"Name" : "ABC Banking",
"scheme":"ABC1",
"createdDate" : "21-01-2018"
}
{
"_id" : ObjectId("5a64d076bfd103df081967ae"),
"status" : "",
"Number" : 53,
"values" : [
{
"date" : "2015-05-18",
"value" : 13.41
},
{
"date" : "2015-05-19",
"value" : 13.45
},
],
"Name" : "ABC Banking",
"scheme":"ABC2",
"createdDate" : "21-01-2018"
}
I am Querying collection based on Number field like
db.getCollection('mfhistories').find({'Number':53})
to get all the documents with this Number.
Now I want to group all the collection with Name 'ABC Banking' into an array. so that I will get result based on Name.
so the result should be like
{
"Name":"ABC Banking",
[
{
"_id" : ObjectId("5a64d076bfd103df081967ae"),
"status" : "",
"Number" : 53,
"values" : [
{
"date" : "2015-05-18",
"value" : 13.41
},
{
"date" : "2015-05-19",
"value" : 13.45
},
],
"scheme":"ABC1",
"createdDate" : "21-01-2018"
},
{
"_id" : ObjectId("5a64d076bfd103df081967ae"),
"status" : "",
"Number" : 53,
"values" : [
{
"date" : "2015-05-18",
"value" : 13.41
},
{
"date" : "2015-05-19",
"value" : 13.45
}
],
"scheme":"ABC2",
"createdDate" : "21-01-2018"
}
]
}
Please help..
Thanks,
J
You can use Aggregation Framework for that:
db.col.aggregate([
{
$match: { Number: 53, Name: "ABC Banking" }
},
{
$group: {
_id: "$Name",
docs: { $push: "$$ROOT" }
}
},
{
$project: {
Name: "$_id",
_id: 0,
docs: 1
}
}
])
$$ROOT is a special variable which captures entire document. More here.
db.mfhistories.aggregate(
// Pipeline
[
// Stage 1
{
$match: {
Number: 53
}
},
// Stage 2
{
$group: {
_id: {
Name: '$Name'
},
docObj: {
$addToSet: '$$CURRENT'
}
}
},
// Stage 3
{
$project: {
Name: '$_id.Name',
docObj: 1,
_id: 0
}
}
]
);

mongodb aggregation match multiple $and on the same field

i have a document like this :
{
"ExtraFields" : [
{
"value" : "print",
"fieldID" : ObjectId("5535627631efa0843554b0ea")
},
{
"value" : "14",
"fieldID" : ObjectId("5535627631efa0843554b0eb")
},
{
"value" : "POLYE",
"fieldID" : ObjectId("5535627631efa0843554b0ec")
},
{
"value" : "30",
"fieldID" : ObjectId("5535627631efa0843554b0ed")
},
{
"value" : "0",
"fieldID" : ObjectId("5535627631efa0843554b0ee")
},
{
"value" : "0",
"fieldID" : ObjectId("5535627731efa0843554b0ef")
},
{
"value" : "0",
"fieldID" : ObjectId("5535627831efa0843554b0f0")
},
{
"value" : "42",
"fieldID" : ObjectId("5535627831efa0843554b0f1")
},
{
"value" : "30",
"fieldID" : ObjectId("5535627831efa0843554b0f2")
},
{
"value" : "14",
"fieldID" : ObjectId("5535627831efa0843554b0f3")
},
{
"value" : "19",
"fieldID" : ObjectId("5535627831efa0843554b0f4")
}
],
"id" : ObjectId("55369e60733e4914550832d0"), "title" : "A product"
}
what i want is to match one or more sets from the ExtraFields array. For example, all the products that contain the values print and 30. Since a value may be found in more than one fieldID (like 0 or true) we need to create a set like
WHERE (fieldID : ObjectId("5535627631efa0843554b0ea"), value : "print")
Where i'm having problems is when querying more than one fields. The pipeline i came up with is :
db.products.aggregate([
{'$unwind': '$ExtraFields'},
{
'$match': {
'$and': [{
'$and': [{'ExtraFields.value': {'$in': ["A52A2A"]}}, {
'ExtraFields.fieldID': ObjectId("5535627631efa0843554b0ea")
}]
}
,
{
'$and': [{'ExtraFields.value': '14'}, {'ExtraFields.fieldID': ObjectId("5535627631efa0843554b0eb")}]
}
]
}
},
]);
This returns zero results, but this is what i want to do in theory. Match all items that contain set 1 AND all that contain set 2.
The end result should look like a faceted search output :
[
{
"_id" : {
"values" : "18",
"fieldID" : ObjectId("5535627831efa0843554b0f3")
},
"count" : 2
},
{
"_id" : {
"values" : "33",
"fieldID" : ObjectId("5535627831efa0843554b0f2")
},
"count" : 1
}
]
Any ideas?
You could try the following aggregation pipeline
db.products.aggregate([
{
"$match": {
"ExtraFields.value": { "$in": ["A52A2A", "14"] },
"ExtraFields.fieldID": {
"$in": [
ObjectId("5535627631efa0843554b0ea"),
ObjectId("5535627631efa0843554b0eb")
]
}
}
},
{
"$unwind": "$ExtraFields"
},
{
"$match": {
"ExtraFields.value": { "$in": ["A52A2A", "14"] },
"ExtraFields.fieldID": {
"$in": [
ObjectId("5535627631efa0843554b0ea"),
ObjectId("5535627631efa0843554b0eb")
]
}
}
},
{
"$group": {
"_id": {
"value": "$ExtraFields.value",
"fieldID": "$ExtraFields.fieldID"
},
"count": {
"$sum": 1
}
}
}
])
With the sample document provided, this gives the output:
/* 1 */
{
"result" : [
{
"_id" : {
"value" : "14",
"fieldID" : ObjectId("5535627631efa0843554b0eb")
},
"count" : 1
}
],
"ok" : 1
}

Find duplicate key in embedded sub document in mongodb

I am trying to craft a query that will allow me to find duplicate keys in subdocument in MongoDB.
It needs to be able to query any number of documents and see what keys are duplicated across them in a subdocument. The key of my subdocument is called attributes and I need to be able to target a particular query of documents and pull out duplicate attribute keys that they all share.
EDIT:
I forgot to mention that I do not know the names of the attributes ahead of time. I need to be able to essentially select distinct attributes that they share and aggregate the values.
Collection Sample:
[
{
sku: '123',
attributes: {
size: 'L',
custom: 7
}
},
{
sku: '456',
attributes: {
size: 'M'
}
},
{
sku: 'abc',
attributes: {
material: 'cotton'
size: 'S'
}
}
]
Desired Result (if possible):
{
size: [' S', 'M', 'L']
}
If the desired result is not possible I would at least like to be able to get back [ 'size' ]
This process needs to be optimized as much as possible and I just cant seem to get a query just right to return what I need, any help is greatly appreciated =)
Here is what I have so far
db.getCollection('myCollection').aggregate([
{ $match: {
_id: { $in: [ObjectId("55158b0bd6076278295cf022"), ObjectId("55158b0bd6076278295cf021"), ObjectId("55158b0bd6076278295cf01f") ] }
}
},
{ $project: { attributes: 1 }},
{ $group: { _id: '$attributes' } }
])
Which products this output:
{
"result" : [
{
"_id" : {
"shirt_size" : "S",
"shirt_color" : "Blue",
"custom_attr" : "adsfasdf"
}
},
{
"_id" : {
"shirt_size" : "M",
"shirt_color" : "Green"
}
},
{
"_id" : {
"shirt_size" : "L",
"shirt_color" : "Red"
}
}
],
"ok" : 1.0000000000000000,
"$gleStats" : {
"lastOpTime" : Timestamp(1427475045, 1),
"electionId" : ObjectId("54f7c1edf8e5ff44cec194b6")
}
}
I feel like it is close and I am just missing the last step :(
I think you need to $unwind the array, and then $group it and use $sum to count the appearance, then everything with sum > 1 is a duplicate.
Links:
http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/
http://docs.mongodb.org/manual/reference/operator/aggregation/group/
http://docs.mongodb.org/manual/reference/operator/aggregation/sum/
The $addToSet(aggregation) returns an array of unique values - http://docs.mongodb.org/manual/reference/operator/aggregation/addToSet/
Using the following aggregation (get unique sizes per Doc):
db.coll1.aggregate([
{$unwind : "$testdoc"},
{$group : {_id: "$_id", size: {$addToSet: "$testdoc.attributes.size"}}}
])
Gives the following result:
{
"result" : [
{
"_id" : ObjectId("551621fe6155a7741a0d328a"),
"size" : [
"M",
"L"
]
},
{
"_id" : ObjectId("551621fe6155a7741a0d328b"),
"size" : [
"L"
]
},
{
"_id" : ObjectId("551621fe6155a7741a0d3289"),
"size" : [
"S",
"M",
"L"
]
}
],
"ok" : 1
}
The following aggregation returns unique sizes across all docs:
db.coll1.aggregate([
{$unwind : "$testdoc"},
{$group :
{_id: "AllSizes", size: {$addToSet: "$testdoc.attributes.size"}}} ])
Result:
{
"result" : [
{
"_id" : "AllSizes",
"size" : [
"S",
"M",
"L"
]
}
],
"ok" : 1
}
Based on the following Docs:
> db.coll1.find().pretty()
{
"_id" : ObjectId("551621fe6155a7741a0d3289"),
"testdoc" : [
{
"sku" : "123",
"attributes" : {
"size" : "L",
"custom" : 7
}
},
{
"sku" : "456",
"attributes" : {
"size" : "M"
}
},
{
"sku" : "abc",
"attributes" : {
"material" : "cotton",
"size" : "S"
}
}
]
}
{
"_id" : ObjectId("551621fe6155a7741a0d328a"),
"testdoc" : [
{
"sku" : "123",
"attributes" : {
"size" : "L",
"custom" : 7
}
},
{
"sku" : "456",
"attributes" : {
"size" : "M"
}
},
{
"sku" : "abc",
"attributes" : {
"material" : "cotton",
"size" : "M"
}
}
]
}
{
"_id" : ObjectId("551621fe6155a7741a0d328b"),
"testdoc" : [
{
"sku" : "123",
"attributes" : {
"size" : "L",
"custom" : 7
}
},
{
"sku" : "456",
"attributes" : {
"size" : "L"
}
},
{
"sku" : "abc",
"attributes" : {
"material" : "cotton",
"size" : "L"
}
}
]
}