Handling 'or' and 'and' condition for fetching data in project - mongodb

I have a collection with data like
"Name": "....",
...
"RoomStatusDetails": [
{
"StatusEntryId": ObjectId("5be1895dbb2c5620c4003ae0"),
"RoomId": "41964158-0131-7b55-7781-a29084879e1a",
"CurrentStatus": ObjectId("5bd17295d2ccda11f0007765"),
"StartDate": ISODate("2018-11-06T05:00:00.0Z"),
"Notes": "",
"Discrepancy": "",
"Waiver": "",
"TFlight": "",
"IsActive": "Inactive"
},
{
"StatusEntryId": ObjectId("5be1896cbb2c5620c4003ae1"),
"RoomId": "41964158-0131-7b55-7781-a29084879e1a",
"CurrentStatus": ObjectId("5bd17295d2ccda11f0007766"),
"StartDate": ISODate("2018-11-06T05:00:00.0Z"),
"Notes": "",
"Discrepancy": "",
"Waiver": "",
"TFlight": "",
"IsActive": "Active"
},
{
"StatusEntryId": ObjectId("5bf4e8a83250041388000edf"),
"RoomId": "d72136ac-b295-d4ea-2d32-0f9ef26b7df1",
"CurrentStatus": ObjectId("5bd17295d2ccda11f0007766"),
"StartDate": ISODate("2018-11-26T23:00:00.0Z"),
"Notes": "",
"Discrepancy": "",
"Waiver": "",
"TFlight": "",
"IsActive": "Active"
},
{
"StatusEntryId": ObjectId("5bf4e8db3250041388000ee0"),
"RoomId": "4c980185-65eb-eece-8176-7f187eed3132",
"CurrentStatus": ObjectId("5bd17295d2ccda11f0007765"),
"StartDate": ISODate("2018-11-18T23:00:00.0Z"),
"Notes": "",
"Discrepancy": "",
"Waiver": "",
"TFlight": "",
"IsActive": "Active"
},
{
"StatusEntryId": ObjectId("5bf4e97f3250041388000ee1"),
"RoomId": "407225eb-2990-263b-4112-068d3ef0e1b2",
"CurrentStatus": ObjectId("5bd17295d2ccda11f0007768"),
"StartDate": ISODate("2018-12-05T23:00:00.0Z"),
"Notes": "",
"Discrepancy": "",
"Waiver": "",
"TFlight": "",
"IsActive": "Active"
}
],
I am trying below lines of code
$this->collection->aggregate(array(
array(
'$project' => array(
'RoomStatusDetails' => array(
'$filter' => array(
'input' => '$RoomStatusDetails',
'as' => 'item',
'cond' => array(
'$or' => [
['$eq' => ['$$item.CurrentStatus', new MongoDB\BSON\ObjectID($this->CAOutOfService)]],
['$eq' => ['$$item.CurrentStatus', new MongoDB\BSON\ObjectID($this->OutOfService)]]
],
['$eq' => ['$$item.IsActive', 'Active']]
)
)
),
'Name' => 1,
'Address' => 1,
'NoOfFloors' => 1,
'Image' => 1,
'Bay' => 1,
'Approved' => 1,
'RoomsDetails' => 1,
'AllotmentsDetails' => 1,
//'TotalNumberOfCapacitiesArray' => 1
)
),
))->toArray();
I am trying to project embedded document RoomStatusDetails and I am trying to fetch only those RoomStatusDetails data where Current Status can be "5bd17295d2ccda11f0007765" or "5bd17295d2ccda11f0007766" which are present in $this->CAOutOfService or $this->OutOfService variables respectively and their IsActive is "Active".
The above code is throwing error "An object representing an expression must have exactly one field: { $or: [ { $eq: [ \"$$item.CurrentStatus\", ObjectId('5bd17295d2ccda11f0007769') ] }, { $eq: [ \"$$item.CurrentStatus\", ObjectId('5bd17295d2ccda11f0007766') ] } ], 0: { $eq: [ \"$$item.IsActive\", \"Active\" ] } }"
Please help!!!

You can build your query like this
db.col.aggregate([{
"$project": {
"RoomStatusDetails": {
"$filter": {
"input": "$RoomStatusDetails",
"as": "stat",
cond: {
"$and": [{
$or: [{
$eq: ["$$stat.CurrentStatus", ObjectId("5bd17295d2ccda11f0007766")]
},
{
$eq: ["$$stat.CurrentStatus", ObjectId("5bd17295d2ccda11f0007765")]
}
]
},
{
$eq: ["$$stat.IsActive", "Active"]
}
]
}
}
}
}
}
])

Related

$lookup aggregation for nested array object

I have category collection which has subcategory embedded object. I need to write aggregation script to first lookup from this collection to storelisting collection. Then add the storelisting fields to the corresponding subcategories.
category
{
"_id": "",
"categoryName": "",
"subCategories": [
{
"subCategoryId": "",
"subCategoryName": "",
"storeListingIds": [
"1",
"2"
]
},
{
"subCategoryId": "",
"subCategoryName": "",
"storeListingIds": [
"3","4","5"
]
}
],
"order": 2,
"createdAt": {
"$date": "2020-12-01T22:26:11.669Z"
},
"updatedAt": {
"$date": "2021-04-27T17:17:25.442Z"
},
"_class": ""
}
storelisting
{
"_id": "1",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "2",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "3",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "4",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "5",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
}
I need to lookup form above collection to storeListing collection. I want all the fields of storeListing also.
Result should be look like this:
{
"_id": "",
"categoryName": "",
"subCategories": [
{
"subCategoryId": "",
"subCategoryName": "",
"storeListingIds": [
"1",
"2"
],
"storeListings":[
{
"_id": "1",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "2",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
}
]
},
{
"subCategoryId": "",
"subCategoryName": "",
"storeListingIds": [
"3","4","5"
],
"storeListings":[
{
"_id": "3",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "4",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
},
{
"_id": "5",
"storeListingName": "",
"storeListingUrl": "",
"catalogueIds": [
""
],
"_class": ""
}
]
}
],
"order": 2,
"createdAt": {
"$date": "2020-12-01T22:26:11.669Z"
},
"updatedAt": {
"$date": "2021-04-27T17:17:25.442Z"
},
"_class": ""
}
Explanation
We perform $lookup for nested storeListingId and store the result in the tmp field
We apply filtering and merge subCategories object with storeListings values
Note: The reason why we use $mergeObjects is to avoid naming every field in subCategories
$map: {
input: "$subCategories",
as: "subCat",
in: {
subCategoryId:"$$subCat.subCategoryId",
subCategoryName:"$$subCat.subCategoryName",
storeListingIds: "$$subCat.storeListingIds",
storeListening: {
$filter: {
input: "$tmp",
cond: {
$in: [ "$$this._id", "$$subCat.storeListingIds" ]
}
}
}
}
}
Try this one:
db.category.aggregate([
{
$lookup: {
from: "storelisting",
localField: "subCategories.storeListingIds",
foreignField: "_id",
as: "tmp"
}
},
{
$addFields: {
tmp: "$$REMOVE",
subCategories: {
$map: {
input: "$subCategories",
as: "subCat",
in: {
"$mergeObjects": [
"$$subCat",
{
storeListings: {
$filter: {
input: "$tmp",
cond: {
$in: [ "$$this._id", "$$subCat.storeListingIds" ]
}
}
}
}
]
}
}
}
}
}
])
MongoPlayground

mongodb select all fields which is not null or empty string

I have mongodb document which has data like this:
{
"_id": "ObjectId(\"5e09db41d4ccee7f500f7326\")",
"time": "ISODate(\"2019-12-30T09:10:53Z\")",
"syslog_fac": 23,
"syslog_sever": 6,
"syslog_tag": "",
"procid": "",
"pid": "-",
"status": "Allowed",
"logtype": "Firewall Logs",
"date": "2019-12-30",
"Module": "01UM",
"Desc": "Theuserloggedout.(UserName",
"Severity_Level": "6",
"Vsys": "public",
"SourceIP": "10.10.0.57",
"ParentGroup": "/netgrup.com.tr",
"LogonTime": "2019/12/3014:07:20",
"LogoutTime": "2019/12/3014:10:53",
"ObversePackets": "0",
"ObverseBytes": "0",
"ReversePackets": "0",
"ReverseBytes": "0",
"LogoutReason": "AnIPaddressconflictoccurred",
"VSys": "",
"PolicyName": "",
"Country": "",
"DestinationIP": "",
"SourcePort": "",
"DestinationPort": "",
"SourceZone": "",
"DestinationZone": "",
"User": "",
"Protocol": "",
"ApplicationName": "",
"Profile": "",
"Type": "",
"Category": "",
"SubCategory": "",
"Page": "",
"Host": "",
"Referer": "",
"Item": "",
"Action": "",
"level": "",
"SourceNatIP": "",
"SourceNatPort": "",
"BeginTime": "",
"EndTime": "",
"SendPkts": 0,
"SendBytes": 0,
"RcvPkts": 0,
"RcvBytes": 0,
"SourceVpnID": "",
"DestinationVpnID": "",
"CloseReason": "",
"Task": "",
"Ip": "",
"VpnName": "",
"AuthenticationMethod": "",
"Command": "",
"user-name": "",
"attack-type": "",
"interface": "",
"packet-count": "",
"rate-number": "",
"file-name": "",
"file-type": "",
"direction": "",
"detect-type": "",
"virus-name": "",
"signature-id": "",
"event-number": "",
"target": "",
"role": "",
"user": ""
}
As you see there are a lot of fields which have an empty string or 0 , so what I want to do is to select only columns that have value except 0 or empty string.
this is my code that I am using to execute query from laravel but return nothings , when I apply that code in mongo directly I get correct data , and return exactly what I want , but return nothings from laravel ,
$data = Logss::raw(function($collection)use ($_id)
{
return $collection->aggregate([
[ '$match' => ['_id'=>'ObjectId(5e09dc63715d622be622c639)']],
[
'$replaceRoot'=> [
'newRoot'=>[
'$arrayToObject'=>[
'$filter'=> [
'input'=> [ '$objectToArray'=>'$$ROOT' ],
'cond'=> [
'$and'=> [
[ '$ne'=> [ '$$this.v', "" ] ],
[ '$ne'=>[ '$$this.v', 0 ] ]
]
]
]
]
]
]
]
]);
});
You can run below query:
db.collection.aggregate([
{ $match: { _id: ObjectId(...) } },
{
$replaceRoot: {
newRoot: {
$arrayToObject: {
$filter: {
input: { $objectToArray: "$$ROOT" },
cond: {
$and: [
{ $ne: [ "$$this.v", "" ] },
{ $ne: [ "$$this.v", 0 ] }
]
}
}
}
}
}
}
])
The idea is pretty simple: you start with $objectToArray to get all the fields as an array. Then you can run $filter to remove all zeros and whitespaces and convert that array back to an object $arrayToObject promoting it to the root level ($replaceRoot).
Mongo Playground

How to $push in deeply nested array of objects in mongodb? [duplicate]

I want add new data my nested array
My document is:
{
"username": "erkin",
"email": "erkin-07#hotmail.com",
"password": "b",
"playlists": [
{
"_id": 58,
"name": "asdsa",
"date": "09-01-15",
"musics": [
{
"name": "INNA - Cola Song (feat. J Balvin)",
"duration": "3.00"
},
{
"name": "blabla",
"duration": "3.00"
}
]
}
]
}
I want add music in this playlist section:
{
"username": "erkin",
"email": "erkin-07#hotmail.com",
"password": "b",
"playlists": [
{
"_id": 58,
"name": "asdsa",
"date": "09-01-15",
"musics": [
{
"name": "INNA - Cola Song (feat. J Balvin)",
"duration": "3.00"
},
{
"name": "blabla",
"duration": "3.00"
},
{
"name": "new",
"duration": "3.00"
}
]
}
]
}
Here is what I tried:
$users->update(
array(
'_id' => new MongoId (Session::get('id')),
'playlists._id' => $playlistId
),
array(
'$push' => array('playlists.musics' => array(
'name' => 'newrecord',
'duration' => '3.00'
))
)
);
Probably something like this where ID is your ObjectId. The first {} are necessary to identify your document. It is not required to use an ObjectId as long as you have another unique identifier in your collection.
db.collection.update(
{ "_id": ID, "playlists._id": "58"},
{ "$push":
{"playlists.$.musics":
{
"name": "test name",
"duration": "4.00"
}
}
}
)
This way it worked for me!
"playlists.$[].musics":
db.collection.update(
{ "_id": ID, "playlists._id": "58"},
{ "$push":
{"playlists.$[].musics":
{
"name": "test name",
"duration": "4.00"
}
}
}
)
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#position-nested-arrays-filtered
I suggest you using arrayFilters since it supports multiple nested documents and clearer.
db.collection.update(
{ "_id": ID},
{ "$push":
{"playlists.$[i].musics":
{
"name": "test name",
"duration": "4.00"
}
}
},
{
arrayFilters: [
{'i._id': 58,},
],
},
)
2022 update:
Full snippet:
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/', maxPoolSize=50)
db = client.name_of_db
collection = db["name_of_collection"]
To push:
collection.find_one_and_update(
{"_id": 'id_of_the_document'},
{"$push": {"key":"value"}})
To push into nested:
collection.find_one_and_update(
{"_id": 'id_of_the_document'},
{"$push": {"key.nested_key":"value"}})

Postgres jsonb, nested array querying to hide specific fields

I have a jsonb data of following format, with nested arrays
{
"outerArray": [
{
"price": {
"amount": 108.95,
"currencyCode": "GBP"
},
"innerArray": [
{
"details": {
"field1": "val1",
"field2": "val2",
"field3": "val3"
},
"otherDetail": {
"date": "2016-07-23",
"time": "19:43:00"
},
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
],
"someField": "values"
},
{
"price": {
"amount": 108.95,
"currencyCode": "GBP"
},
"innerArray": [
{
"details": {
"field1": "val1",
"field2": "val2",
"field3": "val3"
},
"otherDetail": {
"date": "2016-07-23",
"time": "19:43:00"
},
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
],
"someField": "values"
}
]
}
I want to write a retrieve query on this, to maintain same json structure but hide fields "price", "details" , "otherDetail"and "someField"
The retrieved result should look like this
{
"outerArray": [
{
"innerArray": [
{
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
]
},
{
"innerArray": [
{
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
]
}
]
}
Can this be done?
Please always specify a version of PostgreSQL you are using. An example below should work fine for versions v9.5+.
I would approach this by building a JSONB object you need with jsonb_build_object() and jsonb_build_array() functions:
Sample query:
WITH test(data) AS ( VALUES
('{
"outerArray": [
{
"price": {
"amount": 108.95,
"currencyCode": "GBP"
},
"innerArray": [
{
"details": {
"field1": "val1",
"field2": "val2",
"field3": "val3"
},
"otherDetail": {
"date": "2016-07-23",
"time": "19:43:00"
},
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
],
"someField": "values"
},
{
"price": {
"amount": 108.95,
"currencyCode": "GBP"
},
"innerArray": [
{
"details": {
"field1": "val1",
"field2": "val2",
"field3": "val3"
},
"otherDetail": {
"date": "2016-07-23",
"time": "19:43:00"
},
"innerMostArray": [
{
"A1": "A1"
},
{
"B1": "B1"
}
]
}
],
"someField": "values"
}
]}'::JSONB)
)
SELECT
jsonb_build_object(
'outerArray',
array_agg(
jsonb_build_object(
'innerArray',
json_build_array(
json_build_object(
'innerMostArray',
innerArray->'innerMostArray')
)
)
)
) as result
FROM test t,
jsonb_array_elements(t.data->'outerArray') as outerElement,
jsonb_array_elements(outerElement->'innerArray') as innerArray;
Result:
result
----------------------------------------------------------------------------------------------------------------------------------------------------------
{"outerArray": [{"innerArray": [{"innerMostArray": [{"A1": "A1"}, {"B1": "B1"}]}]}, {"innerArray": [{"innerMostArray": [{"A1": "A1"}, {"B1": "B1"}]}]}]}
(1 row)

Mongodb $push in nested array

I want add new data my nested array
My document is:
{
"username": "erkin",
"email": "erkin-07#hotmail.com",
"password": "b",
"playlists": [
{
"_id": 58,
"name": "asdsa",
"date": "09-01-15",
"musics": [
{
"name": "INNA - Cola Song (feat. J Balvin)",
"duration": "3.00"
},
{
"name": "blabla",
"duration": "3.00"
}
]
}
]
}
I want add music in this playlist section:
{
"username": "erkin",
"email": "erkin-07#hotmail.com",
"password": "b",
"playlists": [
{
"_id": 58,
"name": "asdsa",
"date": "09-01-15",
"musics": [
{
"name": "INNA - Cola Song (feat. J Balvin)",
"duration": "3.00"
},
{
"name": "blabla",
"duration": "3.00"
},
{
"name": "new",
"duration": "3.00"
}
]
}
]
}
Here is what I tried:
$users->update(
array(
'_id' => new MongoId (Session::get('id')),
'playlists._id' => $playlistId
),
array(
'$push' => array('playlists.musics' => array(
'name' => 'newrecord',
'duration' => '3.00'
))
)
);
Probably something like this where ID is your ObjectId. The first {} are necessary to identify your document. It is not required to use an ObjectId as long as you have another unique identifier in your collection.
db.collection.update(
{ "_id": ID, "playlists._id": "58"},
{ "$push":
{"playlists.$.musics":
{
"name": "test name",
"duration": "4.00"
}
}
}
)
This way it worked for me!
"playlists.$[].musics":
db.collection.update(
{ "_id": ID, "playlists._id": "58"},
{ "$push":
{"playlists.$[].musics":
{
"name": "test name",
"duration": "4.00"
}
}
}
)
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#position-nested-arrays-filtered
I suggest you using arrayFilters since it supports multiple nested documents and clearer.
db.collection.update(
{ "_id": ID},
{ "$push":
{"playlists.$[i].musics":
{
"name": "test name",
"duration": "4.00"
}
}
},
{
arrayFilters: [
{'i._id': 58,},
],
},
)
2022 update:
Full snippet:
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/', maxPoolSize=50)
db = client.name_of_db
collection = db["name_of_collection"]
To push:
collection.find_one_and_update(
{"_id": 'id_of_the_document'},
{"$push": {"key":"value"}})
To push into nested:
collection.find_one_and_update(
{"_id": 'id_of_the_document'},
{"$push": {"key.nested_key":"value"}})