MongoDB query for a specific field within a document returns empty document - mongodb

For each GSM subscriber, I have a document in "Service" collection and the part I'm querying is as below (Had to omit parts of the document and divide it into two sections since it was quite long), I'm trying to to fetch documentVerifiedDate where documentPurpose and serviceNumber are equal to specific values:
{
"_id": ObjectId("59abee12e4b044ce2d6001b6"),
"service": {
"serviceRequestId": "1335102",
"serviceIndex": "S0",
"accountIndex": "A0",
"serviceUser": {
"isServiceUserSameAsCustomer": "Y",
"isHolder": "N",
"isPayer": "N",
"profileDetails": {
"identificationDetails": {
"identificationDetail": [{
"idType": {
"masterCode": "PASS"
},
"documentPurpose": {
"masterCode": "POID"
},
"idNumber": "9339904299",
"isReceived": "Y",
"isVerified": "Y",
"documentReceivedDate": ISODate("2017-09-05T08:13:25.000+0000"),
"DMSReferenceNo": "85449499",
"documentVerifiedDate": ISODate("2017-09-05T08:13:25.000+0000")
},
{
"idType": {
"masterCode": "REGFORM"
},
"documentPurpose": {
"masterCode": "REGFORM"
},
"isUploaded": "Y",
"isReceived": "Y",
"isVerified": "Y",
"documentUploadedDate": ISODate("2017-09-05T08:13:25.000+0000"),
"DMSReferenceNo": "85449499",
"documentReceivedDate": ISODate("2017-09-05T08:13:25.000+0000"),
"documentVerifiedDate": ISODate("2017-09-05T08:13:25.000+0000")
},
{
"idType": {
"masterCode": "MMS"
},
"documentPurpose": {
"masterCode": "MMS"
},
"isUploaded": "Y",
"isReceived": "Y",
"isVerified": "Y",
"documentUploadedDate": ISODate("2017-09-05T08:13:25.000+0000"),
"DMSReferenceNo": "85449499",
"documentReceivedDate": ISODate("2017-09-05T08:13:25.000+0000"),
"documentVerifiedDate": ISODate("2017-09-05T08:13:25.000+0000")
}
]
},
and also:
"serviceDetails" : {
"serviceNumberCategory" : {
"masterCode" : "NORML"
},
"selfCareAccount" : "Y",
"contractDetails" : {
"startDate" : ISODate("2017-09-03T11:56:58.658+0000"),
"endDate" : ISODate("9999-12-31T00:00:00.000+0000")
},
"technology" : {
"masterCode" : "GSM"
},
"starterKitUpdated" : "Y",
"relatedProject" : "",
"businessType" : {
"masterCode" : "Prepaid"
},
"mobileMoneyAccount" : "Y",
"activatedVia" : {
"masterCode" : "SP"
},
"serviceType" : {
"masterCode" : "GSM"
},
"subServiceType" : {
"masterCode" : "Voice"
},
"serviceNumber" : "9339904299",
"simDetails" : {
I've written below query to fetch documentVerifiedDate where documentPurpose is POID and serviceNumber is 9339904299:
db.Service.find ({
"service.serviceDetails.serviceNumber": "9339902499",
"service.serviceUser.profileDetails.identificationDetails.identificationDetail.0.documentPurpose.masterCode" : "POID"
},
{
"service.serviceUsear.profileDetails.identificationDetails.identificationDetail.0.documentVerifiedDate" : 1,
_id: 0
})
and I'm getting below result:
{
"service" : {
}
}
I'd appreciate it if you could help me understand why above query does not serve the intended purpose, i.e. documentVerifiedDate is not returned.
I've used below link to write the query.
SQL to MongoDB Mapping Chart

From the docs,
$elemMatch, $slice, and $ are the only way to project specific
elements to include in the returned array. For instance, you cannot
project specific array elements using the array index; e.g. {
"instock.0": 1 } projection will not project the array with the first
element.
Use $ positional operator.
Something like
db.Service.find ({
"service.serviceDetails.serviceNumber": "9339904299",
"service.serviceUser.profileDetails.identificationDetails.identificationDetail.documentPurpose.masterCode": "POID"
},
{
"service.serviceUser.profileDetails.identificationDetails.identificationDetail.$": 1
})
This will give you the matching identificationDetail object and you can use the documentVerifiedDate from the document.
Note: serviceNumber in the query is not matching the provided document. I have adjusted query to use the serviceNumber from document.

Related

I am new to mongoDB need a query to delete the collections

I have two collections.
1.Equipment
db.getCollection("Equipment").find({
$and: [
{ $where: 'this._id.length <= 7' },
{ "model": "A505"}
]})
{
"_id" : "1234567",
"locationId" : "DATALOAD",
"model" : "A505",
"subscriberId" : "",
"status" : "Stock",
"headendNumber" : "4"
}
{
"_id" : "P13050I",
"locationId" : "1423110302801",
"model" : "A505",
"subscriberId" : "37",
"status" : "Stock",
"headendNumber" : "4"
}
I will get more than 100 documents (rows) Equipment collection.
2.Subscriber
db.getCollection('Subscriber').find({})
{
"_id" : "5622351",
"equipment" : [
"0018015094E6",
"1234567",
"ADFB70878422",
"M10610TCB052",
"MA1113FHQ151"
]
}
{
"_id" : "490001508063",
"equipment" : [
"17616644510288",
"P13050I",
"M91416EA4251",
"128552270280560"
]
}
In the Subscriber collection, I need to remove (get all the id from Equipment collection loop it) only the matches equipment field.
Forex from the above result, I need to remove only "1234567", and "P13050I"
Expected output.
db.getCollection('Subscriber').find({})
{
"_id" : "5622351",
"equipment" : [
"0018015094E6",
"ADFB70878422",
"M10610TCB052",
"MA1113FHQ151"
]
}
{
"_id" : "490001508063",
"equipment" : [
"17616644510288",
"M91416EA4251",
"128552270280560"
]
}
Please help me, anyone.
You can use the following to update records.
Let's find records which need to deleted and store them in array
var equipments = [];
db.getCollection("Equipment").find({ $and: [
{ $where: 'this._id.length <= 7' },
{ "model": "A505"}
]}).forEach(function(item) => {
equipments.push(item._id)
})
Now, iterate over records of the second collection and update if required.
db.getCollection('Subscriber').find({}).forEach(function(document) => {
var filtered = document.equiment.filter(id => equipments.indexOf(id) < 0);
if(filtered.length < document.equipment.length){
db.getCollection('Subscriber').update({"_id": document.id }, { $set: {'equipment': filtered}})
}
})
.filter(id => equipments.indexOf(id) < 0) will keep entries which is not present in initially populated array equipments and it will persist if there is any change.

Group multi addToSet requests in a single request

I have the following document :
{
"recordKey": "FOO",
"channels": [{
"id": "CH1",
"blocks": []
}, {
"id": "CH2",
"blocks": []
}]
}
In my current use case, I'm doing two requests with addToSet operator for adding new blocks for the channel CH1 or CH2 For example for the channel CH1, I'm doing this:
selector =
{
"$and" : [ {
"recordKey" : "FOO"
}, {
"channels.id" : "CH1"
} ]
}
addChunkRequest = "$addToSet" : {
"channels.$.blocks" : {
"$each" : [ {
"startime" : 101000000,
"blockType" : "DATA",
"fileLoc" : "/tmp/f1",
"nsamples" : 1000
}
query1 = db.collection.update(selector, update)
I'm doing the same think for the channel CH2. Now I want to group the two requests in one request. How can I achieve that ?
Well you cannot of course "update multiple array elements in the one operation", because that is just not presently allowed and a restriction of the positional $ operator.
What you "can" do however is use Bulk Operations to issue "both" operations in a "single request" to the server:
var data = [
{
"channel": "CH1",
"blocks": [{
"startime" : 101000000,
"blockType" : "DATA",
"fileLoc" : "/tmp/f1",
"nsamples" : 1000
}]
},
{
"channel": "CH2",
"blocks": [{
"startime" : 202000000,
"blockType" : "DATA",
"fileLoc" : "/tmp/f2",
"nsamples" : 2000
}]
}
]
var ops = data.map(d => ({
"updateOne": {
"filter": { "recordKey": "FOO", "channels.id": d.channel },
"update": {
"$addToSet": { "channels.$.blocks": { "$each": d.blocks } }
}
}
});
db.collection.bulkWrite(ops);
So it's still "two" operations and that cannot be avoided, however it's only "one" request and response from the server, and that actually helps you quite a lot.

Project with Match in aggregate not working after use substr in mongodb

I have face one use with mongodb.
below is my sample record.
{
"_id" : ObjectId("56fa21da0be9b4e3328b4567"),
"us_u_id" : "1459169911J4gPxpYQ7A",
"us_dealer_u_id" : "1459169911J4gPxpYQ7A",
"us_corporate_dealer_u_id" : "1459169173rgSdxVeMLa",
"us_oem_u_id" : "1459169848CK5yOpXito",
"us_part_number" : "E200026",
"us_sup_part_number" : "",
"us_alter_part_number" : "",
"us_qty" : 0,
"us_sale_qty" : 2,
"us_date" : "20160326",
"us_source_name" : "BOMAG",
"us_source_address" : "",
"us_source_city" : "",
"us_source_state" : "",
"us_zip_code" : "",
"us_alternet_source_code" : "",
"updated_at" : ISODate("2016-03-29T06:34:02.728Z"),
"created_at" : ISODate("2016-03-29T06:34:02.728Z")
}
I have try to get all recored having unique date
So, I have made below query using aggregate
.aggregate(
[
{
"$match":{
"yearSubstring":"2016",
"monthSubstring":"03",
"us_dealer_u_id":"1459169911J4gPxpYQ7A"
}
},
{
"$project":
{
"yearSubstring":{"$substr":["$us_date",0,4]},
"monthSubstring":{"$substr":["$us_date",4,2]},
"daySubstring":{"$substr":["$us_date",6,2]}
}
},
{
"$group":
{
"_id":{"monthSubstring":"$monthSubstring",
"yearSubstring":"$yearSubstring",
"daySubstring":"$daySubstring"
},
"daySubstring":{"$last":"$daySubstring"}
}
},
{"$sort":{"us_date":1}}
]
)
I have try both way to pass year and month (as string and as int)
but I have get blank result.
if I'm remove month and year from condition then record came.
mostly I have try all the diff. diff. solution but result is same.
Thank in advance.
You have written incorrect query.
You don't have yearSubstring and monthSubstring fields on this stage.
{
"$match":{
"yearSubstring":"2016",
"monthSubstring":"03",
"us_dealer_u_id":"1459169911J4gPxpYQ7A"
}
},
You should write as following:
.aggregate(
[
{
"$match":{
"us_dealer_u_id":"1459169911J4gPxpYQ7A"
}
},
{
"$project":
{
"yearSubstring":{"$substr":["$us_date",0,4]},
"monthSubstring":{"$substr":["$us_date",4,2]},
"daySubstring":{"$substr":["$us_date",6,2]}
}
},
{
"$match":{
"yearSubstring":"2016",
"monthSubstring":"03"
}
},
{
"$group":
{
"_id":{"monthSubstring":"$monthSubstring",
"yearSubstring":"$yearSubstring",
"daySubstring":"$daySubstring"
},
"daySubstring":{"$last":"$daySubstring"}
}
},
{"$sort":{"us_date":1}}
]
)
If you want to get other fields, you should include them into projection stage.

how to update property in nested mongo document

I want to update a particular property in a nested mongo document
{
"_id" : ObjectId("55af76e60b0e4b318ba822ec"),
"make" : "MERCEDES-BENZ",
"model" : "E-CLASS",
"variant" : "E 250 CDI CLASSIC",
"fuel" : "Diesel",
"cc" : 2143,
"seatingCapacity" : 5,
"variant_+_fuel" : "E 250 CDI CLASSIC (Diesel)",
"make_+_model_+_variant_+_fuel" : "MERCEDES-BENZ E-CLASS E 250 CDI CLASSIC (Diesel)",
"dropdown_display" : "E-CLASS E 250 CDI CLASSIC (Diesel)",
"vehicleSegment" : "HIGH END CARS",
"abc" : {
"variantId" : 1000815,
"makeId" : 1000016,
"modelId" : 1000556,
"fuelId" : 2,
"segmentId" : 1000002,
"price" : 4020000
},
"def" : {
"bodyType" : 1,
"makeId" : 87,
"modelId" : 21584,
"fuel" : "DIESEL",
"vehicleSegmentType" : "E2"
},
"isActive" : false
}
This is my document. If I want to add or update a value for key "nonPreferred" inside "abc", how do I go about it?
I tried it with this query:
db.FourWheelerMaster.update(
{ "abc.modelId": 1000556 },
{
$Set: {
"abc": {
"nonPreferred": ["Mumbai", "Pune"]
}
}
},
{multi:true}
)
but it updates the whole "abc" structure, removed all key:values inside it and kept only newly inserted key values like below
"abc" : {
"nonPreferred" : [
"Mumbai",
"Pune"
]
},
Can anyone tell me how to update only particular property inside it and not all the complete key?
Instead of using the $set operator, you need to push that array using the $push operator together with the $each modifier to append each element of the value separately as follows:
db.FourWheelerMaster.update(
{ "abc.modelId": 1000556 },
{
"$push": {
"abc.nonPreferred": {
"$each": ["Mumbai", "Pune"]
}
}
},
{ "multi": true }
)

Need help to search document with random field names

I looked through the MongoDB documentation and googled this question but couldn't really find a suitable answer.
encounter a problem where I need to search documents in a collection, but 3 fields name will change from one doc to another even though they are always at the same positions.
In the following example, the 366_DAYS can be 2_HOURS, 35_DAYs etc from document to document, but they will be in the same position.
The _XC4ucB8sEeSybaax341rBg will change to another random string from doc to doc, again it will be at the same position for all docs.
Other fields do not change name and stay at the same position.
I want a query to search for records where debitAmount >=creditAmount or endDate > now().
set02:PRIMARY> db.account.find({ _id: "53e51b1b0cf22cb159fa5f38" }).pretty()
{
"_id" : "53e51b1b0cf22cb159fa5f38",
"_version" : 6,
"_transId" : "e3e96377-a2d2-4b75-a946-f621df182c5e-2719",
"accountBalances" : {
"TEST_TIME" : {
"thresholds" : {
},
"deprovisioned" : false,
"quotas" : {
"366_DAYS" : {
"thresholds" : {
},
"quotaCode" : "366_DAYS",
"credits" : {
"_XC4ucB8sEeSybaax341rBg" : {
"startDate" : ISODate("2014-08-08T18:46:51.351Z"),
"creditAmount" : "86460",
"endDate" : ISODate("2014-08-09T18:48:19Z"),
"started" : true,
"debits" : {
"consolidated" : {
"creationDate" : ISODate("2014-08-08T19:15:55.396Z"),
"debitAmount" : "1300",
"debitId" : "consolidated"
}
},
"creditId" : "_XC4ucB8sEeSybaax341rBg"
}
}
}
},
"expiredReservations" : {
},
"accountBalanceCode" : "TEST_TIME",
"reservations" : {
}
}
},
"subscriberId" : "53e51b1b0cf22cb159fa5f38"
}
Can you use arrays for quotas and credits? That would make the path be the same.
"quotas": [
{
"days": 365,
"thresholds": {},
"credits": [
{
"id": "_XC4ucB8sEeSybaax341rBg"
}
]
}
]
Two cases come to mind. Which one applies to you is unclear to me from the question so providing for both possibilities.
CASE 1:
You will always have either 366_DAYS, 2_HOURS or 35_DAYS inside quotas and only one possible creditId per document. If this is the case, then why replicate the quotaCode and the creditId both as a sub-field and as the key inside quotas and credits respectively. You could alter the structure of your document as follows:
{
"_id": "53e51b1b0cf22cb159fa5f38",
"_version": 6,
"_transId": "e3e96377-a2d2-4b75-a946-f621df182c5e-2719",
"accountBalances": {
"TEST_TIME": {
"thresholds": {},
"deprovisioned": false,
"quotas": {
"thresholds": {
},
"quotaCode": "366_DAYS",
"credits": {
"startDate": ISODate("2014-08-08T18:46:51.351Z"),
"creditAmount": "86460",
"endDate": ISODate("2014-08-09T18:48:19Z"),
"started": true,
"debits": {
"consolidated": {
"creationDate": ISODate("2014-08-08T19:15:55.396Z"),
"debitAmount": "1300",
"debitId": "consolidated"
}
},
"creditId": "_XC4ucB8sEeSybaax341rBg"
}
},
"expiredReservations": {
},
"accountBalanceCode": "TEST_TIME",
"reservations": {
}
}
},
"subscriberId": "53e51b1b0cf22cb159fa5f38"
}
Now the fieldPath for fields in your queries would be:
"accountBalances.TEST_TIME.quotas.credits.creditAmount"
"accountBalances.TEST_TIME.quotas.credits.debits.consolidated.debitAmount"
"accountBalances.TEST_TIME.quotas.credits.startDate"
CASE 2:
quotas and credits may contain more than one subdocument. In this case viktortnk's approach of having quotas and credits as arrays will work. The fieldPath for your queries may then be written as:
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].creditAmount"
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].debits.consolidated.debitAmount"
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].startDate"