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

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")})

Related

Update value of key in Object in nested array of objects in MongoDB

I am trying to update data of "array1.array2._id": ObjectId("627a6fab60dc3c523b396af1") and Set Name to John But it's updating in all array2's first element's name to John.
db.getCollection('tests')
.updateOne({ "array1.array2._id": ObjectId("627a6fab60dc3c523b396af1") },{ $set: { "array1.$[].array2.$.name" : "John" } })
{
"_id" : ObjectId("627a6fab60dc3c523b396aec"),
"array1" : [
{
"array2" : [
{
"_id" : ObjectId("627a6fab60dc3c523b396af1"),
"name" : "test"
},
{
"_id" : ObjectId("627a6fab60dc3c523b396af2"),
"name" : "ABC"
}
],
"_id" : ObjectId("627a6fab60dc3c523b396aed")
},
{
"array2" : [
{
"_id" : ObjectId("627a6fab60dc3c523b396af3"),
"name" : "XYZ"
},
{
"_id" : ObjectId("627a6fab60dc3c523b396af4"),
"name" : "Testing"
}
],
"_id" : ObjectId("627a6fab60dc3c523b396aee")
}
]
}
Based on this great answer by #R2D2, you can do:
db.collection.update({
"array1.array2._id": ObjectId("627a6fab60dc3c523b396af1")
},
{
$set: {
"array1.$[].array2.$[y].name": "John"
}
},
{
arrayFilters: [
{
"y._id": ObjectId("627a6fab60dc3c523b396af1")
}
]
})
As you can see on this playground example

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
}
})

Mongo matching only where first element of array has certain field value

I have a query below that extracts a couple of values from a large nested document. It tells me the user id and the first item name for each order.
This works fine, however I want it to only return the record where the first item's name is not null and is not blank. I can't figure out how to add a second query to the $match operator below to achieve this
db.getCollection('Orders').aggregate
([
{ $match : { "Items.1" : { $exists : true }}, ???},
{ $project: {
_id:0,
'UserId': '$User.EntityId',
'ItemName': {$arrayElemAt: ['$Items.Details.ItemName', 0]}
}
}
]);
Edited to show sample document
{
"_id" : "order-666156",
"State" : "ValidationFailed",
"LastUpdated" : {
"DateTime" : ISODate("2017-09-26T08:54:16.241Z"),
"Ticks" : NumberLong(636420128562417375)
},
"SourceOrderId" : "666156",
"User" : {
"EntityId" : NumberLong(34450),
"Name" : "Bill Baker",
"Country" : "United States",
"Region" : "North America",
"CountryISOCode" : "US",
},
"Region" : null,
"Currency" : null,
"Items" : [
{
"ClientOrderId" : "18740113",
"OrigClientOrderId" : "18740113",
"Quantity" : NumberDecimal("7487.0"),
"TransactDateTime" : {
"DateTime" : Date(-62135596800000),
"Ticks" : NumberLong(0)
},
"Text" : null,
"LocateRequired" : false,
"Details" : {
"ItemName" : "Test Item 1",
"ItemCost" : 1495.20
}
},
{
"ClientOrderId" : "18740116",
"OrigClientOrderId" : "18740116",
"Quantity" : NumberDecimal("241.0"),
"TransactDateTime" : {
"DateTime" : Date(-62135596800000),
"Ticks" : NumberLong(0)
},
"Text" : null,
"LocateRequired" : false,
"Details" : {
"ItemName" : "Test Item 2",
"ItemCost" : 2152.64
}
}
]
}
You need to add the two conditions to your existing $match (not null and not blank) to check the Items as:
$match : { "Items.1" : { $exists : true, "$ne": null,"$ne":""}
If you want to check the element Items[0].Details.ItemName you can doing using the operator $and
{ $match : {
$and: [
{"Items.1" : { $exists : true }},
{"Items.Details.ItemName" : { $ne : null}},
{"Items.Details.ItemName" : { $ne : ""}},
]
}},

Fetch a field from array MongoDB Meteor

Hi I have the following collection structure:
{
"_id" : "HZw2ktDPm6EWnGaFt",
"createdAt" : ISODate("2017-04-16T17:40:59.055Z"),
"pollName" : "",
"entryOwner" : "eHPeQPMd94MQFNXmg",
"question" : [
{
"name" : "Question 1",
"questionId" : "sdPzbn9SWjE46HtM2"
},
{
"name" : "Question 2",
"questionId" : "vpMrpbJ2LZKMLEYKe"
}
],
"sharedWith" : [
{
"id" : "jjX5EDdqMtcyQwd6h",
"name" : "person 1",
"votes" : 0
},
{
"id" : "b3Ctr6LFZMd9smd4B",
"name" : "person 2",
"votes" : 0
}
],
"voters" : [
{
"voterId" : "eHPeQPMd94MQFNXmg",
"questionId" : "vpMrpbJ2LZKMLEYKe",
"optionId" : "EKnYKXEFBWnr4hnCP",
"peopleId" : "b3Ctr6LFZMd9smd4B"
},
{
"voterId" : "eHPeQPMd94MQFNXmg",
"questionId" : "vpMrpbJ2LZKMLEYKe",
"optionId" : "EKnYKXEFBWnr4hnCP",
"peopleId" : "jjX5EDdqMtcyQwd6h"
},
{
"voterId" : "eHPeQPMd94MQFNXmg",
"questionId" : "sdPzbn9SWjE46HtM2",
"optionId" : "rjYLitibXDJjGYKM7",
"peopleId" : "b3Ctr6LFZMd9smd4B"
},
{
"voterId" : "eHPeQPMd94MQFNXmg",
"questionId" : "Q6JiaGFAi2LRHS7GQ",
"optionId" : "wFoduKp23cSYJJG9i",
"peopleId" : "b3Ctr6LFZMd9smd4B"
}
]
}
I would like to get the value of Voters.peopleId by using these values.
"voterId" : "eHPeQPMd94MQFNXmg",
"questionId" : "vpMrpbJ2LZKMLEYKe",
"optionId" : "EKnYKXEFBWnr4hnCP",
I tried this and it didnt work it returns the whole document but what i want as a return is just one field:
var getPeopleId = Polls.findOne({
_id:this.props.poll._id}, {"voters": {
$elemMatch :{voterId:Meteor.userId(),questionId:selectedQuestionId,optionId:selectedOptionId}}})
Many thanks
You've got $elemMatch in the projection (2nd param) instead of the query (1st param). You also need to project the result to only include the first match. Try:
const poll = Polls.findOne(
{
_id:this.props.poll._id,
voters: {
$elemMatch: {
voterId: Meteor.userId(),
questionId: selectedQuestionId,
optionId: selectedOptionId
}
},{
'voters.$': 1
});
// guard against missing keys or no results
const peopleId = poll && poll.voters && poll.voters.peopleId;

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
}

Resources