Getting Specific Array Element - Meteor Mongodb - arrays

I have this structure
{
"_id" : "EbtLm2Nmb79WWryEr",
"notificationByUsers" : {
"all" : [
{
"account_id" : "X5PjY66JAwgoxDb4L",
"date" : ISODate("2016-07-27T13:48:17.154Z"),
"value" : null
},
{
"account_id" : "2C2FKXaKtmeRMNT3E",
"date" : ISODate("2016-07-27T13:53:10.296Z"),
"value" : "Instant"
},
{
"account_id" : "6Np35oj63cavF4RHs",
"date" : ISODate("2016-07-28T07:18:22.696Z"),
"value" : "Instant"
}
]
}
}
and i am querying
db.Collection.findOne({_id: EbtLm2Nmb79WWryEr, 'notificationByUsers.all':{$elemMatch:{account_id: "2C2FKXaKtmeRMNT3E"}}}, {_id:0, 'notificationByUsers.all.$': 1})
it returns in roboMongo
{
"notificationByUsers" : {
"all" : [
{
"account_id" : "2C2FKXaKtmeRMNT3E",
"date" : ISODate("2016-07-27T13:53:10.296Z"),
"value" : "Instant"
}
]
}
But in Meteor it returns all array elements with this query. I want the result with specific array element as working in robomongo.

You can do this using fields projection, like:
MyCollection.findOne({},{ fields : {_id:0, 'notificationByUsers.all':1}});
This will return object like :
{
"notificationByUsers" : {
"all" : [
{
"account_id" : "2C2FKXaKtmeRMNT3E",
"date" : ISODate("2016-07-27T13:53:10.296Z"),
"value" : "Instant"
}
]
}

Related

Mongo Aggregation Get Difference between values of array objects

Good day, I am having difficulty using aggregation in mongodb to get the date difference between two values in an array, my document structure looks as follows:
{
"_id" : ObjectId("5c591420a890362dec70fcf4"),
"tracetag" : "T00005",
"amounts" : [
{
"_id" : ObjectId("5c5915bea890362dec71015a"),
"startdate" : ISODate("2019-02-15T04:49:02.000+0000"),
"enddate" : ISODate("2019-02-15T04:50:05.000+0000"),
"amount" : 18.975946800811833,
},
{
"_id" : ObjectId("5c5915bea890362dec71015b"),
"startdate" : ISODate("2019-02-16T04:49:02.000+0000"),
"enddate" : ISODate("2019-02-16T04:51:52.000+0000"),
"amount" : 3.5755730555836203,
},
{
"_id" : ObjectId("5c5915bea890362dec71015c"),
"startdate" : ISODate("2019-02-17T04:49:02.000+0000"),
"enddate" : ISODate("2019-02-17T04:50:04.000+0000"),
"amount" : 2.3937573313380383,
}
],
}
the number of "amounts" entries are not fixed, so it could be 1 or 50 etc.
for each document, I would like to get the difference between the 'enddate' and 'startdate' (aka the duration) and I would like to sum the duration (lets call this totalduration). I can do the total 'amount' without issues, but getting the duration gives me error ""cant $subtract aarray from a array", my aggregation looks like this:
{
"$project" : {
"tracetag" : 1.0,
"totalamount" : {
"$sum" : "$amounts.amount"
},
"totalduration" : {
"$sum" : {
"$subtract" : [
"$amounts.enddate",
"$amounts.startdate"
]
}
}
}
},
OK so I managed to answer my own question: the 'amounts' need to be split using the $unwind operator, then a field can be added to each record (duration), in my case I wanted the duration in minutes. Afterwards I grouped everything again
{
"$unwind" : { "path" : "$amounts" }
},
{
"$addFields" : {
"duration" : { "$divide" : [ { "$subtract" : [
"$enddate", "$startdate" ]}, 60000.0 ] }
}
},

mongo query - getting a specific object (its `_id` is known) from array of object BUT this array is also a part of list of documents

how can I query to get the specific message from either inbox or outbox given that I have its _id --> i.e. message id.
this is my route
get("/getSpecificMessage/{Message_id}", (req, res) => {..}
what I can do is find all the buyer/dealer and then go through inbox/outbox of all the buyer/dealer and then find the message with _id i.e. message_id
--> can I do it better then that.
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e1"),
"address" : {
"proper_address" : "sarai kale khan",
"lat" : 28.58894,
"long" : "77.25692"
},
"name" : "prashant",
"password" : "jfalksdjlk;jasdl",
"email" : "prashant#gmail.com",
"inbox" : [
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e4"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"from" : "1#1.com",
"message" : "message_1"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e3"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"from" : "2#2.com",
"message" : "message_2"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e2"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"from" : "3#3.com",
"message" : "message_3"
}
],
"outbox" : [
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e7"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"to" : "1#1.com",
"message" : "message_4"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e6"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"to" : "1#1.com",
"message" : "message_5"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e5"),
"date" : ISODate("2018-09-04T23:03:41.627Z"),
"to" : "1#1.com",
"message" : "message_6"
}
],
"__v" : 0
}
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e8"),
"address" : {
"proper_address" : "najafgarah",
"lat" : 28.58894,
"long" : "77.25692"
},
"name" : "rahul",
"password" : "jkalsjdflasdl",
"email" : "rahul#gmail.com",
"inbox" : [
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083eb"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"from" : "1#1.com",
"message" : "message_1"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083ea"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"from" : "2#2.com",
"message" : "message_2"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083e9"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"from" : "3#3.com",
"message" : "message_3"
}
],
"outbox" : [
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083ee"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"to" : "1#1.com",
"message" : "message_4"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083ed"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"to" : "1#1.com",
"message" : "message_5"
},
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083ec"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"to" : "1#1.com",
"message" : "message_6"
}
],
"__v" : 0
}
So if I have the _id = 5b8f0f4de276dd1e0ff083ea and I want
{
"_id" : ObjectId("5b8f0f4de276dd1e0ff083ea"),
"date" : ISODate("2018-09-04T23:03:41.639Z"),
"from" : "2#2.com",
"message" : "message_2"
}
I am not sure if you want it using MongoDB scripts or your app language (Nodejs if I am mistaken)
This is how it works on Mongo Shell Script
db.MODEL.find( { _id: DOCUMENT_ID },
{ inbox: { $elemMatch: { _id: MESSAGE_ID } } } )
Documentation is here
If this is not what you want, please update your post and add which language/framework you are using
This is what you could do using the aggregation framework:
var oId = new ObjectId("5b8f0f4de276dd1e0ff083ea");
db.collection.aggregate({
$match: { // can be skipped but I'd personally keep it because this will use an index on "input._id"/"output._id" (if there is one) to filter out irrelevant documents
$or: [
{ "inbox": { $elemMatch: { "_id": oId } } },
{ "outbox": { $elemMatch: { "_id": oId } } },
]
}
}, {
$project: {
result: {
$concatArrays: [
{ $filter: { "input": "$inbox", "cond": { $eq: [ "$$this._id", oId ] } } },
{ $filter: { "input": "$outbox", "cond": { $eq: [ "$$this._id", oId ] } } }
]
}
}
}, {
$unwind: "$result" // flatten the result array
}, {
$replaceRoot: {
"newRoot": "$result" // move "result" contents all the way up
}
})

Why I can't get the full document form array?

I have this document in stored in my collection:
{ "_id" : ObjectId("5707b95b8415b224a48a0b2d"),
"companyId" : ObjectId("570269639caabe24e4e4043e"),
"descriptions" : [
{ "id" : ObjectId("5707b95b8415b224a48a0b2a"), "description" : "test" },
{ "id" : ObjectId("570cd8164fff3a20f88c0dc9"), "description" : "test1" },
{ "id" : ObjectId("570ce6ba4fff3a052c8c570f"), "description" : "etr" },
{ "id" : ObjectId("570cf1b64fff3a1a14d71716"), "description" : "43" },
{ "id" : ObjectId("570cf1b64fff3a1a14d71717"), "description" : "43" },
{ "id" : ObjectId("570cf1b64fff3a1a14d71719"), "description" : "345" }
],
"options" : [
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a"), "description" : "test" },
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a"), "description" : "test1" }
]
}
Now I'm trying to get the objects from the options array that are matching the descriptionId and here is how I'm doing it
db.CustomFields.find({companyId: ObjectId("570269639caabe24e4e4043e")},{"options.descriptionId": ObjectId("5707b95b8415b224a48a0b2a")})
But the result contains only the descriptionId - the description property is missing.
here is how the result looks like:
{ "_id" : ObjectId("5707b95b8415b224a48a0b2d"),
"options" : [
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a") },
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a") }
]
}
Why my query is not returning the full document from the array, but only a part of it? Can you give me a push?
EDIT
This is what I'm expecting to get from the query
{ "_id" : ObjectId("5707b95b8415b224a48a0b2d"),
"options" : [
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a", "description" : "test") },
{ "descriptionId" : ObjectId("5707b95b8415b224a48a0b2a", "description" : "test1") }
]
}
You need to include the other query with "options.descriptionId" together with the companyId query and use projection to return just the array you want.
The following shows this:
db.customFields.find(
{
"companyId": ObjectId("570269639caabe24e4e4043e"),
"options.descriptionId": ObjectId("5707b95b8415b224a48a0b2a")
},
{ "options": 1 }
);
Output
{
"_id" : ObjectId("5707b95b8415b224a48a0b2d"),
"options" : [
{
"descriptionId" : ObjectId("5707b95b8415b224a48a0b2a"),
"description" : "test"
},
{
"descriptionId" : ObjectId("5707b95b8415b224a48a0b2a"),
"description" : "test1"
}
]
}
Try this
db.CustomFields.find({companyId: ObjectId("570269639caabe24e4e4043e"),"options.descriptionId": ObjectId("5707b95b8415b224a48a0b2a")})

Returning a subset of array items in MongoDB

Can anyone offer advice on how I would return a subset of array items? For example, let's suppose I have a collection of documents (similar to the example below) that contains a simple _id key and a key that contains an array of objects.
I would like to find all _id's and the matching objects that match a simple criteria:
// campaigns
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok",
},
{
"date" : "2015-06-12",
"source" : "nike"
},
{
"date" : "2015-06-14",
"source" : "adidas"
},
]
},
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
}
I would like my result to contain the _id and any matching objects for, say, a date value of "2015-06-17"
// GOAL => To generate a result set that looks like:
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok",
}
]
},
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
}
Use the aggregation framework to achieve the desired result. The following pipeline consists of a $match operator stage as the first step to filter the documents that should pass through the pipeline.
The next stage is the $addFields operator that allows you to output documents that contain all existing fields from the input documents and newly added fields.
Within this step you can use the $filter operator to select a subset of an array to return based on the specified filter:
db.collection.aggregate([
{ "$match": {
"campaignData.date" : "2015-06-17"
} },
{ "$addFields": {
"campaignData": {
"$filter": {
"input": "$campaignData",
"cond": {
"$eq": ["$$this.date", "2015-06-17"]
}
}
}
} }
])
Result:
/* 0 */
{
"result" : [
{
"_id" : "Mike's Marathon",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
}
]
},
{
"_id" : "Jacob's Jamboree",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "keen"
}
]
},
{
"_id" : "Fred's C25K",
"campaignData" : [
{
"date" : "2015-06-17",
"source" : "nike"
},
{
"date" : "2015-06-17",
"source" : "reebok"
}
]
}
],
"ok" : 1
}

Create array with query MongoDb

I have this Collection
{
"_id" : ObjectId("55555555ffffff000010200a"),
"name" : "foo"
}
{
"_id" : ObjectId("55555555ffffff000010200e"),
"name" : "bar"
}
{
"_id" : ObjectId("55555555ffffff000010200f"),
"name" : "baz"
}
{
"_id" : ObjectId("55555555ffffff000010200b"),
"name" : "biz"
}
and I want an array ids
I did this
db.mycollection.find({}, {_id: 1})
and return
{
"_id" : ObjectId("55555555ffffff000010200a")
}
{
"_id" : ObjectId("55555555ffffff000010200e")
}
{
"_id" : ObjectId("55555555ffffff000010200f")
}
{
"_id" : ObjectId("55555555ffffff000010200b")
}
{
"_id" : ObjectId("55555555ffffff000010200c")
}
{
"_id" : ObjectId("55555555ffffff0000103111")
}
Can I have an array?
id['55555555ffffff0000103111','55555555ffffff0000103111','555555555ffffff0000103111','55555555ffffff0000103111']
Option 1: If an array of subdocuments is acceptable, you can just append .toArray() to the find query.
> db.test.find({}, {_id:1}).toArray()
[
{
"_id" : ObjectId("53270b12d111b9bf595f4270")
},
{
"_id" : ObjectId("53270b14d111b9bf595f4271")
},
{
"_id" : ObjectId("53270b16d111b9bf595f4272")
}
]
Option 2: Another option is to use the aggregation framework.
> db.test.aggregate([{$group:{_id:null, ids:{$push:"$_id"}}}, {$project:{_id:0, ids:1}}])
{
"result" : [
{
"ids" : [
ObjectId("53270b12d111b9bf595f4270"),
ObjectId("53270b14d111b9bf595f4271"),
ObjectId("53270b16d111b9bf595f4272")
]
}
],
"ok" : 1
}
Option 3: Or you can use forEach in the shell like this:
> var myIds = new Array()
> db.test.find({},{_id:1}).forEach(function(myDoc){myIds.push(myDoc._id.str)})
> myIds
[
"53270b12d111b9bf595f4270",
"53270b14d111b9bf595f4271",
"53270b16d111b9bf595f4272"
]
Use distinct to turn a single column into an array:
db.mycollection.distinct('_id', function(err, list){
//list is an array of ObjectId
});

Resources