how to project array element in document at specific position - mongodb

I have a document like this.
{ "_id" : ObjectId("5c6cc08a568f4cdf7870b3a7"),
"phone" : {
"cell" : [
"854-6574-545",
"545-6456-545"
],
"home" : [
"5474-647-574",
"455-6878-758"
]
}
}
I want to display output like this.
output
{
"_id" : ObjectId("5c6cc08a568f4cdf7870b3a7"),
"phone" : {
"cell" : [
"854-6574-545"
]
}
}
please advice.

Use $slice to project number from array.
Query:
db.collection.find({},
{
"phone.cell": {
$slice: 1
},
"phone.home": 0
})
Result:
{
"_id": ObjectId("5c6cc08a568f4cdf7870b3a7"),
"phone": {
"cell": [
"854-6574-545"
]
}
}
Query 2:
db.collection.find({},
{
"_id": 0,
"phone.cell": {
$slice: 1
},
"phone.home": 0
})
Result 2:
{
"phone": {
"cell": [
"854-6574-545"
]
}
}
** Final Query - using aggregate**
db.collections.aggregate([{'$match':{'phone.cell':{'$exists':true}}},
{'$project':{'_id':1,'phone.cell':{$slice:['$phone.cell',1,1]}}}])
** Output **
{
"_id" : ObjectId("5c6cc08a568f4cdf7870b3a7"),
"phone" : {
"cell" : [
"545-6456-545"
]
}
}

Related

Return field of column in MongoDB

I have this table, and I want to filter some fields of it. The table looks like this:
/* 1 */
{
"_id" : ObjectId("5ce7db93db1ec10d08941d44"),
"name" : "john",
"age" : "22",
"group" : "A",
"nodes" : [
{
"name1" : "some_name1",
"status" : "completed"
}
]
}
/* 2 */
{
"_id" : ObjectId("5ce7e2fd726ed9434c32aaba"),
"name" : "mike",
"age" : "23",
"group" : "B",
"nodes" : [
{
"dev_name" : "some_name_dev1",
"status" : "not completed"
},
{
"dev_name" : "some_name_dev2",
"status" : "completed"
}
]
}
/* 3 */
{
"_id" : ObjectId("5ce7e36c726ed9434c32aabc"),
"name" : "anne",
"age" : "24",
"group" : "C",
"status" : "pending"
}
/* 4 */
{
"_id" : ObjectId("5ce7f05e726ed9434c32aabe"),
"name" : "jane",
"age" : "27",
"group" : "D",
"nodes" : [
{
"dev_name" : "some_name_dev6",
"status" : "not completed"
},
{
"dev_name" : "some_name_dev7"
}
]
}
And what I actually want to return is this (a simple object with "status" if nodes does not exist, and an array if nodes exists:
/* 1 */
[{
"status" : "completed"
}]
/* 2 */
[{
"status" : "not completed"
},
{
"status" : "completed"
}]
/* 3 */
{
"status" : "pending"
}
/* 4 */
[{
"status" : "not completed"
}]
I did this:
db.getCollection('user').find(
{
$or: [
{
"status": { $ne:null }
},
{
"nodes.status":{ $exists: true }
}
]
},
{
'status': 1,
'nodes.status': 1,
'_id': 0
}
)
and the result is this, and I am a little bit stuck:
/* 1 */
{
"nodes" : [
{
"status" : "completed"
}
]
}
/* 2 */
{
"nodes" : [
{
"status" : "not completed"
},
{
"status" : "completed"
}
]
}
/* 3 */
{
"status" : "pending"
}
/* 4 */
{
"nodes" : [
{
"status" : "not completed"
},
{}
]
}
How can I obtain what I want (getting rid of nodes field)? Thank you for your time!
EDIT:
db.getCollection('user').find(
{
$or: [
{
"status": { $ne:null }
},
{
"nodes.status":{ $exists: true }
}
]
},
{
'status': 1,
'nodes.status': 1,
'_id': 0
},
[ { "$project": { "status": { "$ifNull" : ["$nodes.status", ""] } } } ]
)
You are going to the right direction using {$project: <expression>} to change the format of your return document. But I don't think the $ifNull has been used correctly. According to the doc, the input of the $ifNull is
{ $ifNull: [ <expression>, <replacement-expression-if-null> ] }
Full Query:
db.getCollection('user').find(
{
$or: [
{
"status": { $ne:null }
},
{
"nodes.status":{ $exists: true }
}
]
},
{
'status': { "$ifNull" : ["$status", "$nodes.status"] },
'_id': 0
})
Edit: Using aggregation instead of simple find(), as $ifNull operator is only available using aggregation.
db.collection.aggregate([
{
$match: { #behaves like the find operator
$or: [
{
"status": {
$ne: null
}
},
{
"nodes.status": {
$exists: true
}
}
]
}
},
{
$project: {
"status": {
"$ifNull": [
"$status",
"$nodes.status"
]
},
"_id": 0
}
}
])
output:
[
{
"status": [
"completed"
]
},
{
"status": [
"not completed",
"completed"
]
},
{
"status": "pending"
},
{
"status": [
"not completed"
]
}
]

mongodb return just the subdocument by querying the field

I have a structure like this:
{
"_id" : ObjectId("5b155aa3e7179a6034c6dd5b"),
"pinnedKpi" : {
"Ver01" : [
"130",
"138",
"122",
"134"
],
"Ver02" : [
"265",
"263",
"142",
"264"
],
"Ver03" : [ ],
"Ver04" : [
"126",
"134",
"122",
"138"
]
},
"email" : "john#doe.ca",
Is it possible to do a query like return just the array where email = john#doe.ca and pinnedKpi.Ver01 ---> ["130","138","122","134"]
Just use this:
db.collection.find({ // find all documents
"email": "john#doe.ca" // where the "email" field equals some value
}, {
"_id": 0, // do not return the "_id" field (included by default)
"pinnedKpi.Ver01": 1 // only return the "pinnedKpi.Ver01" field
})
if array doesn't need to be the root element of response, you can use the following query to return pinnedKpi.Ver01 array with email criteria and presence of Ver01 element in pinnedKpi array :
db.test1.find(
{"email" : "john#doe.ca", "pinnedKpi.Ver01" : {"$exists" : true}},
{"pinnedKpi.Ver01" : 1}
);
Which output :
{
"_id" : ObjectId("5b155aa3e7179a6034c6dd5b"),
"pinnedKpi" : {
"Ver01" : [
"130",
"138",
"122",
"134"
]
}
}
If array result need to be the root element, you can use aggregation framework to achieve this :
db.test1.aggregate(
[
{
$match: {email:"john#doe.ca","pinnedKpi.Ver01":{$exists:true}}
},
{
$replaceRoot: {
newRoot: "$pinnedKpi"
}
},
{
$project: {
Ver01:1
}
},
]
);
Output :
{
"Ver01" : [
"130",
"138",
"122",
"134"
]
}

How do get the last substring using the MongoDB aggregation framework?

Let's say I have these documents
> db.coll.find().toArray()
[
{
"_id" : ObjectId("5a36c3e218948d0722457078"),
"locality" : "Nasimi, Baku, Azerbaijan"
},
{
"_id" : ObjectId("5a36c3e218948d0722457079"),
"locality" : "Garland, TX, USA"
},
{
"_id" : ObjectId("5a36c3e218948d072245707a"),
"locality" : "Halytskyi District, Lviv, Lviv Oblast, Ukraine"
},
{
"_id" : ObjectId("5a36c3e218948d072245707b"),
"locality" : "Tozeur, Tunisia"
}
]
I would like to get only the country, i.e. whatever is after the last comma (', ').
e.g.
[
"Azerbaijan",
"USA",
"Ukraine",
"Tunisia"
]
I've managed to get the index of the first comma and what is after that but I can't figure out how to to get the last one.
db.coll
.aggregate([
{
$project: {
lastIndexOf: { $indexOfBytes: [ '$locality', ', ' ] },
locality: '$locality',
}
},
{
$project: {
lastIndexOfPlusTwo: { $add: [ '$lastIndexOf', 2 ] },
locality: '$locality',
}
},
{
$project: { country: { $substr: [ '$locality', '$lastIndexOfPlusTwo', -1 ] } }
}
]).pretty()
{
"_id" : ObjectId("5a36c3e218948d0722457078"),
"country" : "Baku, Azerbaijan"
}
{
"_id" : ObjectId("5a36c3e218948d0722457079"),
"country" : "TX, USA"
}
{
"_id" : ObjectId("5a36c3e218948d072245707a"),
"country" : "Lviv, Lviv Oblast, Ukraine"
}
{
"_id" : ObjectId("5a36c3e218948d072245707b"),
"country" : "Tunisia"
}
This works but it loads all the results in memory in the JavaScript Mongo Shell but would be ideal if it can be done with a single MongoDB aggregation command.
var res2 = db.coll.aggregate();
res2 = res2.toArray().map(function(doc) {
var lastIndex = doc.locality.lastIndexOf(',');
return doc.locality.slice(lastIndex + 2);
});
[ "Azerbaijan", "USA", "Ukraine", "Tunisia" ]
Maybe with $let, $split?
You can try below aggregation query.
{"$arrayElemAt":["$$locality",-1]} to access the last element from the array.
db.coll.aggregate([{"$project":{
"_id":0,
"last":{
"$let":{
"vars":{"locality":{"$split":["$locality",","]}},
"in":{"$arrayElemAt":["$$locality",-1]}
}
}
}}])

Mongodb array object count by value

I have json with the following structure
db.testCollection.insert(
{
"m_id": 2,
"sys_data":[
{"sattr":
{
"size": 2,
"d_data":
[
{"d_counter": 2,
"client_ip":"1.1.1.1",
"d_date":"02/01/01"}
{"d_counter": 2,
"client_ip":"1.1.1.1",
"d_date":"02/01/01"}
{"d_counter": 2,
"client_ip":"1.1.1.1",
"d_date":"03/01/01"}
]
}
}
]
}
db.testCollection.insert(
{
"m_id": 2,
"sys_data":[
{"sattr":
{
"size": 2,
"d_data":
[
{"d_counter": 2,
"client_ip":"1.1.1.1",
"d_date":"02/01/01"}
]
}
}
]
}
I want to get the count where d_date ='02/01/01', So the output for above json is 3. (two from first json and one from the second)
Use the aggregation framework to get the count. This allows you to $unwind the deeply nested embedded documents (with the help of the dot notation), filter out the unwanted documents using the $match operator which is similar to the find() query and use the $sum accumulator operator in the $group pipeline to determine the count of the matching documents.
Something like this:
Populate test collection:
db.testCollection.insert([
{
"m_id" : 2,
"sys_data" : [
{
"sattr" : {
"size" : 2,
"d_data" : [
{
"d_counter" : 2,
"client_ip" : "1.1.1.1",
"d_date" : "02/01/01"
},
{
"d_counter" : 2,
"client_ip" : "1.1.1.1",
"d_date" : "02/01/01"
},
{
"d_counter" : 2,
"client_ip" : "1.1.1.1",
"d_date" : "03/01/01"
}
]
}
}
]
},
{
"m_id" : 2,
"sys_data" : [
{
"sattr" : {
"size" : 2,
"d_data" : [
{
"d_counter" : 2,
"client_ip" : "1.1.1.1",
"d_date" : "02/01/01"
}
]
}
}
]
}])
Run the aggregation pipeline:
var pipeline = [
{
"$match": {
"sys_data.sattr.d_data.d_date" : "02/01/01"
}
},
{
"$unwind": "$sys_data"
},
{
"$unwind": "$sys_data.sattr.d_data"
},
{
"$match": {
"sys_data.sattr.d_data.d_date" : "02/01/01"
}
},
{
"$group": {
"_id": null,
"count": { "$sum": 1 }
}
}
];
db.testCollection.aggregate(pipeline);
Sample output:
/* 0 */
{
"result" : [
{
"_id" : null,
"count" : 3
}
],
"ok" : 1
}
Check out this docs from mongodb
db.testCollection.count( { d_date : "02/01/01" } )
Also, the above is equivalent to:
db.testCollection.find( { d_date: "02/01/01" } ).count()
If you feel slow performance check this question.

Find exactly match array or having all value of array in MongoDb

I have collection entry like that
[
{
shape : [{id:1,status:true},{id:2,status:false}]
},
{
shape : [{id:1,status:true}]
}
]
I want to fetch data which exactly match array , means contain all ele. of array.
Ex. where shape.id = [1,2] / [ {id: [1,2] } ] (any one is prefer)
then it should return only
[
{
shape : [{id:1,status:true},{id:2,status:false}]
}
]
So help me if is there any native mongodb query .
Thanks
--ND
Here is much simpler query;
db.shapes.find({'shape.id':{$all:[1,2]},shape:{$size:2}});
If mongo documents as below
{
"_id" : ObjectId("54eeb68c8716ec70106ee33b"),
"shapeSize" : [
{
"shape" : [
{
"id" : 1,
"status" : true
},
{
"id" : 2,
"status" : false
}
]
},
{
"shape" : [
{
"id" : 1,
"status" : true
}
]
}
]
}
Then used below aggregation to match the criteria
db.collectionName.aggregate({
"$unwind": "$shapeSize"
}, {
"$match": {
"$and": [{
"shapeSize.shape.id": 2
}, {
"shapeSize.shape.id": 1
}]
}
}, {
"$project": {
"_id": 0,
"shape": "$shapeSize.shape"
}
})