How to get only the objects meeting one criteria in mongodb? - mongodb

I have example collection:
db.books.find()
{ "author" : "Coetzee", "is_favourite" : true, "version" : 1 }
{ "author" : "Coetzee", "is_favourite" : true, "version" : 1 }
{ "author" : "Coetzee", "is_favourite" : false, "version" : 2 }
{ "author" : "King", "is_favourite" : false, "version" : 2 }
{ "author" : "Cohen", "is_favourite" : true, "version" : 2 }
{ "author" : "Cohen", "is_favourite" : false, "version" : 3 }
{ "author" : "Picasso", "is_favourite" : true, "version" : 3 }
by running this:
db.books.aggregate([
{ $match: {"is_favourite":{ $ne: true}}},
{ $group: { _id: "$author"}}
])
I get the following:
{ "_id" : "Cohen" }
{ "_id" : "King" }
{ "_id" : "Coetzee" }
what should I do to get only the objects meeting "is_favourte": false?
In this particular case I'm interested in getting only "author": "King"

Assuming that you want author where is_favourite is always false, you could use this :
db.books.aggregate([
{
$group:{
_id:"$author",
is_fav:{
$push:"$is_favourite"
}
}
},
{
$match:{
is_fav:{
$nin:[
true
]
}
}
},
{
$project:{
_id:1
}
}
],{
allowDiskUse: true
})
returns
{ "_id" : "King" }

Related

MongoDB - Find duplicated elements in record property

I'm struggling to identified duplicated elements in my MongoDB records, here is my problem :
I have a Mongo collection named "elements".
Example of a record in this collection :
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
I would like to identify records where the array "items" contains objects with the same "ref_id".
In my example we can see that the last two objects of the "items" array have the same "ref_id" : ObjectId("5d1b2204e851271e80c823d5").
I tried a bunch of aggregate function but unfortunately couldn't came out with a solution.
The following query can get us the expected output:
db.elements.aggregate([
{
$unwind:"$items"
},
{
$group:{
"_id":"$_id",
"root":{
$first:"$$ROOT"
},
"items":{
$push:"$items"
},
"distinctItems":{
$addToSet: "$items.ref_id"
}
}
},
{
$match:{
$expr:{
$ne:[
{
$size:"$items"
},
{
$size:"$distinctItems"
}
]
}
}
},
{
$addFields:{
"root.items":"$items"
}
},
{
$replaceRoot:{
"newRoot":"$root"
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
{
"_id" : ObjectId("5d654b9d7d0ab652c42315f2"),
"name" : "B",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
}
]
}
Output:
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
Explanation: We are populating an array of distinct ref_id from each document and matching if the size of the populated array is equal to the size of actual items array.

MongoDB sort by join result with aggregate lookup

I have two collections user and post
> db.user.find().pretty()
{
"_id" : ObjectId("5d1473bc1b48d9309580a9de"),
"user_id" : NumberLong(1),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9df"),
"user_id" : NumberLong(2),
"region" : "KR",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e0"),
"user_id" : NumberLong(3),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e1"),
"user_id" : NumberLong(4),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1487fc1b48d9321ff5dc1f"),
"user_id" : NumberLong(5),
"region" : "US",
"is_join" : true
}
> db.post.find().pretty()
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e2"),
"post_id" : NumberLong(1),
"user_id" : NumberLong(3),
"body" : "hi"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e3"),
"post_id" : NumberLong(2),
"user_id" : NumberLong(1),
"body" : "hello"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e4"),
"post_id" : NumberLong(3),
"user_id" : NumberLong(2),
"body" : "go"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e5"),
"post_id" : NumberLong(4),
"user_id" : NumberLong(4),
"body" : "python"
}
{
"_id" : ObjectId("5d14941b1b48d93314907345"),
"post_id" : NumberLong(5),
"user_id" : NumberLong(1),
"body" : "aa"
}
I want to join via mongo aggregate lookup operation.
So I made query like this.
db.user.aggregate([
{
'$match': {
'region': 'US',
}
},
{
'$lookup': {
'from': 'post',
'localField': 'user_id',
'foreignField': 'user_id',
'as': 'user'
}
},
{
'$project': {
'_id': 0,
'user.post_id': 1
}
}
])
Result
{ "user" : [ { "post_id" : NumberLong(2) }, { "post_id" : NumberLong(5) } ] }
{ "user" : [ { "post_id" : NumberLong(1) } ] }
{ "user" : [ { "post_id" : NumberLong(4) } ] }
{ "user" : [ ] }
As you know that post_id is unordered.
But I want to sort it descending.
Desired result
{ "user" : [ { "post_id" : NumberLong(1) } ] }
{ "user" : [ { "post_id" : NumberLong(2) } ] }
{ "user" : [ { "post_id" : NumberLong(4) } ] }
{ "user" : [ { "post_id" : NumberLong(5) } ] }
Even Better
{ "user" : [ 1, 2, 4, 5 }] }
How can I modify aggregate query?
Thanks.
You can do following to get what you want:
1) $unwind the user array
2) use $sort to sort all documents with post_id
3) use $group as the next stage in your aggregation query, and push user.post_id to form one sorted user array from all the docs:
db.user.aggregate([
{
'$match': {
'region': 'US',
}
},
{
'$lookup': {
'from': 'post',
'localField': 'user_id',
'foreignField': 'user_id',
'as': 'user'
}
},
{
$unwind : {
path : "$user",
preserveNullAndEmptyArrays : true
}
},
{
$sort : {
'user.post_id' : 1
}
},
{
$group : {
_id : null,
user : {
$push : "$user.post_id"
}
}
}
])
Read more about $sort , $unwind and $group for more information.

MongoDB perform join with aggregate

I have two collections User and Post.
User
user_id
region
is_join
Post
post_id
user_id
body
is_block
From perspective of rdb, User:Post relationship is 1:N.
Each user can write multiple post.
For example, currently documents is inserted like this.
User
> db.user.find()
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d2"), "user_id" : NumberLong(1), "region" : "US", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d5"), "user_id" : NumberLong(2), "region" : "KR", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d8"), "user_id" : NumberLong(3), "region" : "US", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28da"), "user_id" : NumberLong(4), "region" : "KR", "is_join" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28dc"), "user_id" : NumberLong(5), "region" : "US", "is_join" : true }
Post
> db.post.find()
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d3"), "post_id" : NumberLong(1), "user_id" : NumberLong(1), "body" : "first", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d4"), "post_id" : NumberLong(4), "user_id" : NumberLong(1), "body" : "fourth", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d6"), "post_id" : NumberLong(2), "user_id" : NumberLong(2), "body" : "second", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d7"), "post_id" : NumberLong(3), "user_id" : NumberLong(2), "body" : "third", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d9"), "post_id" : NumberLong(5), "user_id" : NumberLong(3), "body" : "fifth", "is_block" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28db"), "post_id" : NumberLong(6), "user_id" : NumberLong(4), "body" : "sixth", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28dd"), "post_id" : NumberLong(7), "user_id" : NumberLong(5), "body" : "seven", "is_block" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28de"), "post_id" : NumberLong(8), "user_id" : NumberLong(5), "body" : "eight", "is_block" : false }
To perform join via aggregate, there is more condition that have to apply.
User region='US', is_join=true
Posts created by user with the result of number 1
Post is_block=false
Sort by post_id
(Optional) If user do not wrote any post, except it. I know it can be perform through preserveNullAndEmptyArrays, but I think it cause performance issue.
Desired result
{
"posts" : [
{
"post_id" : NumberLong(1),
"body" : "first",
"is_block" : false
},
{
"post_id" : NumberLong(2),
"body" : "second",
"is_block" : false
},
{
"post_id" : NumberLong(3),
"body" : "third",
"is_block" : false
},
{
"post_id" : NumberLong(4),
"body" : "fourth",
"is_block" : false
},
{
"post_id" : NumberLong(8),
"body" : "eight",
"is_block" : false
}
]
}
post_id = 5 was excluded by is_block=true
post_id = 6 was excluded by is_join=false
post_id = 7 was excluded by is_block=true
And whole result is sorted by post_id.
I'm new at mongodb So, maybe I thinking too much in the form of a relational database.
And I don't know it can be perform on NoSQL.
Is there any way about it?
Any suggestion, very appreciate.
Thanks.
You can achieve such result using lookup pipeline operator.
const region = 'US';
const is_join = true;
const is_block = false;
const query = [
{
$match: {
region: region,
is_join: is_join
}
},
{
$lookup: {
let: { user_id: "$user_id" },
from: 'posts',
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$$user_id", "$user_id"], },
{ $eq: ["$is_block", is_block] }
]
}
}
},
{
$sort: {
post_id: 1
}
}
],
as: "posts"
}
},
{
$unwind: "$posts"
},
{
$group:{
_id: "mygroup",
posts: {
$push: {
post_id: "$posts.post_id",
body: "$posts.body",
is_block: "$posts.is_block",
}
}
}
},
{
$project:{
_id: false
}
}
]
db.users.aggregate(query)
OUTPUT
{
"posts" : [
{
"post_id" : 1,
"body" : "first",
"is_block" : false
},
{
"post_id" : 4,
"body" : "fourth",
"is_block" : false
},
{
"post_id" : 8,
"body" : "eight",
"is_block" : false
}
]
}
Try this -
To join two collection, you can use aggregation as -
User.aggregate([{
'$match': { 'region':'US', 'is_join': true } // match from users collection
}, {
$lookup: { // it will aggregate the result from both collection
from: 'posts',
localField: '_id',
foreignField: 'user_id',
as: 'posts'
}
},
{"$unwind":"$posts"},
{$match : { "posts.is_block" : false } }, // check inside post collection
{$sort : { "posts.post_id" : 1}}, // sort the data
], (err, users) => {
if (err) return callback(err, null);
console.log('users :', users);
});

Return specific array value field in aggregate

I have a issue in MongoDB i'm trying to build a very complex aggregate query, and its work almost as i want it, but i still have trobles, and the problems is i need to move a spefiect field so i can use it later.
My aggregate look like this right now.
db.getCollection('travel_sights').aggregate([{
'$match': {
'preview.photo' : {
'$exists':true
},
'_id': {
'$in' : [ObjectId("5b7af9701fbad410e10f32f7")]
}
}
},{
'$unwind' : '$preview.photo'
}, {
'$lookup':{
'from' : 'media_data',
'localField' : '_id',
'foreignField':'bind',
'as':'media'
}
}])
and it will return data like this.
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7affea1fbad441494a663b"),
"sort" : 0
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7b002d1fbad441494a663c"),
"sort" : 0
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7b00351fbad441494a663d"),
"sort" : 0,
"primary" : false
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
and what you can se the last data have preview.photo.primary on it, and this field i want to return when i'm done with my aggregate query.
My final query look like this:
db.getCollection('travel_sights').aggregate([{
'$match': {
'preview.photo' : {
'$exists':true
},
'_id': {
'$in' : [ObjectId("5b7af9701fbad410e10f32f7")]
}
}
},{
'$unwind' : '$preview.photo'
}, {
'$lookup':{
'from' : 'media_data',
'localField' : '_id',
'foreignField':'bind',
'as':'media'
}
},{
'$unwind':'$media'
},{
'$project' : {
'preview' : 1,
'media': 1,
}
}, {
'$group': {
'_id':'$media._id',
'primary': {
'$first':'$preview'
}
}
}])
The problem here is when i want $preview return so i can find the primary about it, its allways only return the first where the value not exists, if i use $push the problem is i get every thing.
is there a way so i can pick the right primary value in my return? have trying $addFields to but whitout eny kind of lock.
Travel_sights data:
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"city_id" : ObjectId("5b6d0cb6222d4c70b803eaeb"),
"activated" : true,
"deleted" : false,
"url" : "url is here",
"name" : "title of it here",
"updated_at" : ISODate("2018-08-22T17:22:27.000Z"),
"content" : "content here",
"preview" : {
"photo" : [
{
"id" : ObjectId("5b7affea1fbad441494a663b"),
"sort" : 0
},
{
"id" : ObjectId("5b7b002d1fbad441494a663c"),
"sort" : 0
},
{
"id" : ObjectId("5b7b00351fbad441494a663d"),
"sort" : 0,
"primary" : true
},
{
"id" : ObjectId("5b7d9baa1fbad410de638bbb"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bae1fbad410e10f32f9"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bb11fbad441494a663e"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bb41fbad4ff97273402"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bb71fbad4ff99527e82"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bbb1fbad410de638bbc"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bbe1fbad410e10f32fa"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bc11fbad441494a663f"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bc41fbad4ff97273403"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bc71fbad4ff99527e83"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bca1fbad410de638bbd"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bcd1fbad441494a6640"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bd01fbad4ff97273404"),
"sort" : 0
}
]
}
}
3 sample foto bind data here:
{
"_id" : ObjectId("5b7affea1fbad441494a663b"),
"file-name" : "55575110311__0F115282-B5A0-4654-AA44-B7DC2C682992.jpeg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
]
}
{
"_id" : ObjectId("5b7b002d1fbad441494a663c"),
"file-name" : "55575110748__E7B07EFD-9F7E-40D6-8B57-38F708E4C0C0.jpeg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
],
"description" : "this is secoudn demo!",
"title" : "demo 3"
}
{
"_id" : ObjectId("5b7b00351fbad441494a663d"),
"file-name" : "paris2.jpg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
],
"description" : "this is a demo1 :)",
"title" : "demo"
}
You can filter out the element from the array where the primary field exists using $filter aggregation and then easily $group with the media._id field and get the $first document value.
Finally your query will be
db.getCollection("travel_sights").aggregate([
{ "$match": {
"preview.photo" : { "$exists":true },
"_id": { "$in" : [ ObjectId("5b7af9701fbad410e10f32f7") ] }
}},
{ "$addFields": {
"preview.photo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$preview.photo",
"as": "photo",
"cond": { "$ne": [ "$$photo.primary", undefined ] }
}}, 0
]
}
}},
{ "$lookup":{
"from" : "media_data",
"localField" : "_id",
"foreignField": "bind",
"as": "media"
}},
{ "$unwind":"$media" },
{ "$project" : { "preview" : 1, "media": 1, }},
{ "$group": {
"_id": "$media._id",
"primary": { "$first": "$preview" }
}}
])

Mongodb : How should I get original Json structure after filter the records based on requirement?

I am new to mongodb.
I have a Json document in collection like :
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"orgid" : {
"KeyValue" : "DD3342",
"service" : "<all>",
"keytype" : "MCN"
}
},
{
"orgid" : {
"notifytype" : {
"optout" : true
},
"keytype" : "MCN",
"keyvalue" : "<all>",
"service" : "MVPN"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "abc.com",
"notifytype" : {
"alert" : true
},
"id" : 123456.0000000000000000
}
},
{
"order" : {
"id" : 135246.0000000000000000,
"date" : "2015-03-17",
"adminemail" : "abc.com"
}
}
]
}
I would like to filter above json document with following condition:
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, {$match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{$group: {_id: "$_id", assignment: {$push: "$assignment"}}}
// ,{$project : { usercbid : $usercbid, defaultnotifytype : 1, calendar : 1, assignment: 1} }
]
)
printjson(result);
Result of above query is :
{
"result" : [
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"alert" : true
},
"id" : 123456
}
}
]
}
],
"ok" : 1
}
But my final result lost the following original content:
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
How should I append above original content with filtered records?
Thanks,
$Fisrt is the operator which helps you getting the required output.
When you do a $Group, the result of the $Group pipeline operator contains only those fields which are specified inside the $Group pipeline operator.
So, from your query we can notice that you are grouping based on "_Id" and you are selecting only "assignment" key field, so the OUTPUT of this group pipeline operator will contain only those 2 fileds ( "_ID" and "assignment" ).
To make sure that the other left out feilds ( usercbid, defaultnotifytype , calendar ) to be part of the $Group pipeline output, we need to mention that explicitly in the Group pipeline using $First as below :
{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
$First Returns the value that results from applying an expression to the first document in a group of documents that share the same group by key.
Please check the below query, it will help you in fetching the required output :
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, { $match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
]
).pretty();