How to group in mongodb withtout including _id - mongodb

so I want to result as :
{
"id" : 888789999,
"name" : "Malaysian with Attendance Allowance",
}
but I tried
{$group : {
'id' : '$profiles.id',
'name' : {$first:'$profiles.name'},
}}
an I get an error :
"errmsg" : "The field 'id' must be an accumulator object",

you can try this, to group by profile id and get first name, add project if you need id without underscore.
In group, except _id other fields should have accumulation or aggregation
{$group : {
'_id' : '$profiles.id',
'name' : {$first:'$profiles.name'},
}}
If you don't want to include _id then
{$group : {
_id: null,
'id' : {$first:'$profiles.id'},// any accumulation which you need
'name' : {$first:'$profiles.name'},
}}

db.collectionName.aggregate(
[
{
$group : {
id : { profiles: { $profiles: "$id" }},
name : {$first:{profiles:{$profiles:"name"}}}
}
}
]
)

Related

BulkWriteError - MongoDB

I understand this error occurs because of _id duplication in my code. I'm writing an aggregation pipeline where there are no unique fields in _id and I guess that's where duplication occurs. I want to either insert duplicate _id (which I suppose I can't) or create unique _id object.
I tried using BSON.ObjectId() to generate unique id with insert_many() but it says it cannot encode object: {ObjectId('5d4a71227e16ce9599a8d6ac')}, of type:
col.aggregate([{
'$project' : {
'date' : {'$dateToString' : {'format' : '%Y-%m-%d', 'date':
{'$dateFromString': {'dateString': '$createdAt'}}}},
'cinemaid' : 1,
'planid' : 1,
'location' : 1,
'creditworth' : 1,
'amountpaid' : 1,
'upsize' : 1
}
},
{
'$group' : {
'_id' : {'location' : '$location', 'cinemaid' : '$cinemaid', 'planid' :
'$planid', 'date' : '$date',
'credithworth' : {'$sum' : '$creditworth' },
'addons' : { '$sum' : '$amountpaid'},
'upsize' : {'$sum' : '$upsize'}
}
}])
I expect each aggregated document either with unique _id or duplicate _id to be inserted into collection.

MongoDB find documents with a matching field in another collection

known = [{ system_id : 1234},
{ system_id : 1235},
{ system_id : 1236},
{ system_id : 1237}]
peeps = [
{system_id: 1234, name : bob},
{system_id: 1232, name : jim},
{system_id: 1231, name : dave},
{system_id: 1237, name : jeff}
]
If I have the above two collections, and I want to find documents in the peeps collection that have system_ids that exist in documents in the known collection, how can that be done? I'm currently running an aggregation across peeps where I find all the unique combinations of name and system_id, but I need to exclude anything that is not in the known collection.
db.peeps.aggregate({
$lookup : {
from : "known",
localField : "system_id",
foreignField : "system_id",
as : "someField"
}
},{
$match : {
"someField.0" : {
$exists : true
}
}
},{
$project : {
"someField" : 0
}
})
This will output all those peeps which have system_id matched in knwon.

MongoDB Group by field and show array of grouped items?

I have a collection of Projects in where projects are like this:
{
"_id" : ObjectId("57e3e55c638cb8b971"),
"allocInvestor" : "Example Investor",
"fieldFoo" : "foo bar",
"name" : "GTP 3 (Roof Lease)"
}
I want to receive a list of projects grouped by allocInvestor field and only show fields: name and id
If I use aggregate and $group like this:
db.getCollection('projects').aggregate([
{"$group" : {
_id:"$allocInvestor", count:{$sum:1}
}
}
])
I receive a count of project per allocInvestor but I need is to receive the list of allocInvestor with subarray of projects per allocInvestor.
I'm using meteor by the way in case that helps. But I first want to get the query right on mongodb then try for meteor.
You can use $push or $addToSet to create a list of name and _id per every group.
$push allows duplicates and $addToSet does not add an element to the list again, if it is already there.
db.getCollection('projects').aggregate([
{ "$group" : { _id : "$allocInvestor",
count : {$sum : 1},
"idList" : {"$addToSet" : "$_id"},
"nameList" : {"$addToSet":"$name"}
}
}
]);
To get the name and _id data in a single list:
db.getCollection('projects').aggregate([
{ "$group" : { _id : "$allocInvestor", "projects" : {"$addToSet" : {id : "$_id", name: "$name"}}}},
{"$project" : {"_id" : 0, allocInvestor : "$_id", "projects" : 1 }}
]);
Use the $$ROOT operator to reference the entire document and then use project to eliminate the fields that you do not require.
db.projects.aggregate([
{"$group" : {
"_id":"$allocInvestor",
"projects" : {"$addToSet" : "$$ROOT"}
}
},
{"$project" : {
"_id":0,
"allocInvestor":"$_id",
"projects._id":1
"projects.name":1
}
}
])

How to project specific fields from a document inside an array?

here is a typical document
{
title : 'someTitle',
places : [{name : 'someName', location : 'someLocation'}, {name ...}]
}
I have the following query
var qs = {title : 'someTitle', places : {$elemMatch : {name : 'someName' } } };
where I select a document which matches the title and which contains a document entry within its 'places' array that has name equal to 'someName'. However the issue is that the entries within the places array are large documents, and I only need a couple of fields from that document. I tried projecting the fields like so but it did not work.
var projection = {'places.$.name': 1, 'places.$.location' : 1};
Which is supposed to return an array with a document containing only the 'name' and 'location' property.
I got the following error
Can't canonicalize query: BadValue Cannot specify more than one positional proj. per query.
to be clear, I would like to accomplish this without the aggregate framework
You are doing it wrong. According to the documentation
Only one positional $ operator may appear in the projection document.
But you still need to use the $ operator to get the expected result:
var qs = { title : 'someTitle', 'places.name' : 'someName' };
var projection = {'places.$': 1 };
db.collection.find(qs, projection);
Which returns:
{
"_id" : ObjectId("564f52d7d9a433df958b5630"),
"places" : [
{
"name" : "someName",
"location" : "someLocation"
}
]
}
Also you don't need the $elemMatch operator here use "dot notation" instead.
Now if what you want is an array of "name" and "location" for each subdocument in the array then aggregation is the way to go.
db.collection.aggregate([
{ '$match': {
'title' : 'someTitle',
'places.name' : 'someName'
}},
{ '$project': {
'places': {
'$map': {
'input': '$places',
'as': 'place',
'in': {
'name': '$$place.name',
'location': '$$place.location'
}
}
}
}}
])
Which yields:
{
"_id" : ObjectId("564f52d7d9a433df958b5630"),
"places" : [
{
"name" : "someName",
"location" : "someLocation"
},
{
"name" : "bar",
"location" : "foo"
}
]
}
For the fields inside an array, you can project them the same as in embedded object
var projection = {'places.name': 1, 'places.location' : 1};
Check this guideline
https://docs.mongodb.com/manual/reference/operator/aggregation/project/#include-specific-fields-from-embedded-documents

$add operation returns null value

I have collection with document structure :
{
'year' : 2014,
'month' : 1
}
I am executing the following operation :
db.collname.aggregate(
[
{
$project : {
'year100' : {$multiply : ["$year" , 100]},
'result' : { '$add' : ['$year100', '$month'] }
}
}
]
);
I get the following result :
{
"result" : [
{
"_id" : ObjectId("5563596c515a88832210f0e4"),
"year100" : 201400.0000000000000000,
"result" : null
},
}
Why is add operation returuning null value as against to actual value ? Please help.
MongoDb not allow to used same fields in project to arithmetic operation instead of one $project used two different projects like this :
db.collname.aggregate({ $project : { 'year100' : {$multiply : ["$year" , 100]} ,"month":"$month"} },{"$project":{"year100":1,"result":{"$add":["$year100","$month"]}}})