Project with Match in aggregate not working after use substr in mongodb - 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.

Related

MongoDB- Add new field from existing array

I am the beginner of the MongoDB
Here I mentioned my database schema
{
"_id" : ObjectId("5e72067973c1241068a13647"),
"client_id" : "1001",
"dependent" : [
{
"dependent_name" : "asdsa",
"dependent_id" : "DE100"
},
{
"dependent_name" : "fdggd",
"dependent_id" : "DE101"
}
]
}
I want to add new field based on client_id and dependent_id
Here I mentioned My query but cannot able to get my expected result
db.collection.update({"client_id" : "1001","dependent.dependent_id":"DE101"}, {"$push": {"reason":"expired"}})
I am Expected Result is
{
"_id" : ObjectId("5e72067973c1241068a13647"),
"client_id" : "1001",
"dependent" : [
{
"dependent_name" : "asdsa",
"dependent_id" : "DE100"
},
{
"dependent_name" : "fdggd",
"dependent_id" : "DE101",
"reason":"expired"
}
]
}
so anyone help me to solve this
db.collection.update({"client_id" : "1001","dependent.dependent_id":"DE101"},
{$set:
{"dependent.$.reason":"expired"}})
Try this it works for me using $
As i am also new to mongodb, as i tried, i can give you suggestion to update whole document or replace it.
both way i tried, and query is as below.
Update
db.updateColl.update({ 'dependent.dependent_id': 'DE101' },
{
$set: {
"dependent": [
{
"dependent_name": "asdsa",
"dependent_id": "DE100"
},
{
"dependent_name": "fdggd",
"dependent_id": "DE101",
"reason": "expired"
}
]
}
});
Replace
db.updateColl.replaceOne({ 'dependent.dependent_id': 'DE101' }, {
"dependent": [
{
"dependent_name": "asdsa",
"dependent_id": "DE100"
},
{
"dependent_name": "fdggd",
"dependent_id": "DE101",
"reason": "expired"
}
]
})
may be it can help you. if any suggestion regarding it wellcome.

How to update Meteor array element inside a document

I have a Meteor Mongo document as shown below
{
"_id" : "zFndWBZTvZPgSKXHP",
"activityId" : "aRDABihAYFoAW7jbC",
"activityTitle" : "Test Mongo Document",
"users" : [
{
"id" : "b1#gmail.com",
"type" : "free"
},
{
"id" : "JqKvymryNaCjjKrAR",
"type" : "free"
},
],
}
I want to update a specific array element's email with custom generated id using Meteor query something like the below.
for instance, I want to update the document
if 'users.id' == "b1#gmail.com" then update it to users.id = 'SomeIDXXX'
So updated document should looks like below.
{
"_id" : "zFndWBZTvZPgSKXHP",
"activityId" : "aRDABihAYFoAW7jbC",
"activityTitle" : "Test Mongo Document",
"users" : [
{
"id" : "SomeIDXXX",
"type" : "free"
},
{
"id" : "JqKvymryNaCjjKrAR",
"type" : "free"
},
],
}
I have tried the below but didnt work.
Divisions.update(
{ activityId: activityId, "users.id": emailId },
{ $set: { "users": { id: _id } } }
);
Can someone help me with the relevant Meteor query ? Thanks !
Your query is actually almost right except for a small part where we want to identify the element to be updated by its index.
Divisions.update({
"activityId": "aRDABihAYFoAW7jbC",
"users.id": "b1#gmail.com"
}, {
$set: {"users.$.id": "b2#gmail.com"}
})
You might need the arrayFilters option.
Divisions.update(
{ activityId: activityId },
{ $set: { "users.$[elem].id": "SomeIDXXX" } },
{ arrayFilters: [ { "elem.id": "b1#gmail.com" } ], multi: true }
);
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/
You need to use the $push operator instead of $set.
{ $push: { <field1>: <value1>, ... } }

Spring data MongoDb query based on last element of nested array field

I have the following data (Cars):
[
{
"make" : “Ferrari”,
"model" : “F40",
"services" : [
{
"type" : "FULL",
“date_time" : ISODate("2019-10-31T09:00:00.000Z"),
},
{
"type" : "FULL",
"scheduled_date_time" : ISODate("2019-11-04T09:00:00.000Z"),
}
],
},
{
"make" : "BMW",
"model" : “M3",
"services" : [
{
"type" : "FULL",
"scheduled_date_time" : ISODate("2019-10-31T09:00:00.000Z"),
},
{
"type" : "FULL",
“scheduled_date_time" : ISODate("2019-11-04T09:00:00.000Z"),
}
],
}
]
Using Spring data MongoDb I would like a query to retrieve all the Cars where the scheduled_date_time of the last item in the services array is in-between a certain date range.
A query which I used previously when using the first item in the services array is like:
mongoTemplate.find(Query.query(
where("services.0.scheduled_date_time").gte(fromDate)
.andOperator(
where("services.0.scheduled_date_time").lt(toDate))),
Car.class);
Note the 0 index since it's first one as opposed to the last one (for my current requirement).
I thought using an aggregate along with a projection and .arrayElementAt(-1) would do the trick but I haven't quite got it to work. My current effort is:
Aggregation agg = newAggregation(
project().and("services").arrayElementAt(-1).as("currentService"),
match(where("currentService.scheduled_date_time").gte(fromDate)
.andOperator(where("currentService.scheduled_date_time").lt(toDate)))
);
AggregationResults<Car> results = mongoTemplate.aggregate(agg, Car.class, Car.class);
return results.getMappedResults();
Any help suggestions appreciated.
Thanks,
This mongo aggregation retrieves all the Cars where the scheduled_date_time of the last item in the services array is in-between a specific date range.
[{
$addFields: {
last: {
$arrayElemAt: [
'$services',
-1
]
}
}
}, {
$match: {
'last.scheduled_date_time': {
$gte: ISODate('2019-10-26T04:06:27.307Z'),
$lt: ISODate('2019-12-15T04:06:27.319Z')
}
}
}]
I was trying to write it in spring-data-mongodb without luck.
They do not support $addFields yet, see here.
Since version 2.2.0 RELEASE spring-data-mongodb includes the Aggregation Repository Methods
The above query should be
interface CarRepository extends MongoRepository<Car, String> {
#Aggregation(pipeline = {
"{ $addFields : { last:{ $arrayElemAt: [$services,-1] }} }",
"{ $match: { 'last.scheduled_date_time' : { $gte : '$?0', $lt: '$?1' } } }"
})
List<Car> getCarsWithLastServiceDateBetween(LocalDateTime start, LocalDateTime end);
}
This method logs this query
[{ "$addFields" : { "last" : { "$arrayElemAt" : ["$services", -1]}}}, { "$match" : { "last.scheduled_date_time" : { "$gte" : "$2019-11-03T03:00:00Z", "$lt" : "$2019-11-05T03:00:00Z"}}}]
The date parameters are not parsing correctly. I didn't spend much time making it work.
If you want the Car Ids this could work.
public List<String> getCarsIdWithServicesDateBetween(LocalDateTime start, LocalDateTime end) {
return template.aggregate(newAggregation(
unwind("services"),
group("id").last("services.date").as("date"),
match(where("date").gte(start).lt(end))
), Car.class, Car.class)
.getMappedResults().stream()
.map(Car::getId)
.collect(Collectors.toList());
}
Query Log
[{ "$unwind" : "$services"}, { "$group" : { "_id" : "$_id", "date" : { "$last" : "$services.scheduled_date_time"}}}, { "$match" : { "date" : { "$gte" : { "$date" : 1572750000000}, "$lt" : { "$date" : 1572922800000}}}}]

Find in nested arrays mongodb

Below the data structure of my services in MongoDB:
"serviceInfo" : {
"title" : "Lorem ipsum",
"options" : [
{
"startDate" : ISODate("2018-10-01T00:00:00.000Z"),
"endDate" : ISODate("2018-10-31T00:00:00.000Z"),
"availabilities" : [
{
"businessDay" : {
"id" : 1,
"name" : "Monday"
},
}
]
}
]
Now, I want to query all the services available the Monday during the period between startDate and endDate.
I tried this code but I have an empty array as result instead of my document.
db.collection('services').find({
'serviceInfo.options': {
$elemMatch: {
'startDate': { $lte: new Date(req.query.date) },
'endDate': { $gte: new Date(req.query.date) },
'availabilities': {
$elemMatch: {
'businessDay.id': req.query.day
}
}
}
}
}).toArray()
I guess my problem is in the nested array availabilities but I don't find the correct way to do the query.
Thanks in advance for your help.
I found my problem.
'businessDay.id' expected an Int32 and parseInt(req.query.day) did the trick.

Query to count number of occurrence in array grouped by day

I have the following document structure:
(trackerEventsCollection) =
{
"_id" : ObjectId("5b26c4fb7c696201040c8ed1"),
"trackerId" : ObjectId("598fc51324h51901043d76de"),
"trackingEvents" : [
{
"type" : "checkin",
"eventSource" : "app",
"timestamp" : ISODate("2017-08-25T06:34:58.964Z")
},
{
"type" : "power",
"eventSource" : "app",
"timestamp" : ISODate("2017-08-25T06:51:23.795Z")
},
{
"type" : "position",
"eventSource" : "app",
"timestamp" : ISODate("2017-08-25T06:51:23.985Z")
}
]
}
I would like to write a query that would count number of trackingEvents with type "type" : "power" grouped by day. This seems to be quite tricky to me because parent document does not have date and I should rely on timestamp field that belongs to the trackingEvents array members.
I'm not really experienced mongodb user and couldn't understand how can this be achieved so far.
Would really appreciate any help, thanks
To process your nested array as a separate documents you need to use $unwind. In the next stage you can use $match to filter out by type. Then you can group by single days counting occurences. The point is that you have to build grouping key containing year, month and day like in following code:
db.trackerEvents.aggregate([
{ $unwind: "$trackingEvents" },
{ $match: { "trackingEvents.type": "power" } },
{
$group: {
_id: {
year: { $year:"$trackingEvents.timestamp" },
month:{ $month:"$trackingEvents.timestamp" },
day: { $dayOfMonth:"$trackingEvents.timestamp" }
},
count: { $sum: 1 }
}
}
])