I'm using https://github.com/perplexhub/rsql-jpa-specification to filter entities of my database in Spring with the QuerydslPredicateExecutor and RSQLQueryDslSupport fromio.github.perplexhub:rsql-querydsl-spring-boot-starter package.
I want to filter nested collection (OneToMany) is empty or have an specific value.
how can I achieve to get a filter like describe?
This is my search query so far :
filter=deleted==false ;properties.deleted==false
Example of data is:
{
"test":[
{
"id":"252355",
"deleted":false,
"properties":[
{
"id":"sgdegegwe",
"deleted":false
}
]
},
{
"id":"252555",
"deleted":false,
"properties":[
]
}
]
}
I want to filter Query to achieve this result, which is the best way or how to integrate a custom
=isEmpty=''
operation.
The End Result should be
{
"test":[
{
"id":"252355",
"deleted":false,
"properties":[
{
"id":"sgdegegwe",
"deleted":false
}
]
},
{
"id":"252555",
"deleted":false,
"properties":[
]
}
]
}
and not
{
"test":[
{
"id":"252355",
"deleted":false,
"properties":[
{
"id":"sgdegegwe",
"deleted":false
}
]
}
]
}
Related
I'm having a collection called vehicles whose structure is given below.
[
{
"vehicleType":"car",
"parts":[
{
"partName":"engine",
"buyingPrice":145.00,
"sellingPrice":200.00
},
{
"partName":"brake",
"buyingPrice":50.00,
"sellingPrice":70.00
},
{
"partName":"wheel",
"buyingPrice":70.00,
"sellingPrice":75.00
}
]
},
{
"vehicleType":"bike",
"parts":[
{
"partName":"engine",
"buyingPrice":1450.00,
"sellingPrice":2000.00
},
{
"partName":"brake",
"buyingPrice":507.00,
"sellingPrice":170.00
},
{
"partName":"wheel",
"buyingPrice":70.00,
"sellingPrice":75.00
}
]
},
{
"vehicleType":"car",
"parts":[
{
"partName":"engine",
"buyingPrice":1450.00,
"sellingPrice":2000.00
},
{
"partName":"brake",
"buyingPrice":50.00,
"sellingPrice":170.00
},
{
"partName":"wheel",
"buyingPrice":700.00,
"sellingPrice":750.00
}
]
}
]
I want to update the sellingPrice as 500.00 if the partName is brake and sellingPrice is <= 170.00. I excuted the below query, but it is updating the value only for the 1st object.
db.getCollection("vehicles").find({})
.forEach(function(v){
v.parts.forEach(function(p){
if(p.partName=="brake" && p.sellingPrice<=170.00){
p.sellingPrice=500.00;
print(v);
}
})
})
Below is the output of above query
[
{
"vehicleType":"bike",
"parts":[
{
"partName":"engine",
"buyingPrice":1450.00,
"sellingPrice":2000.00
},
{
"partName":"brake",
"buyingPrice":507.00,
"sellingPrice":500.00
},
{
"partName":"wheel",
"buyingPrice":70.00,
"sellingPrice":75.00
}
]
},
{
"vehicleType":"car",
"parts":[
{
"partName":"engine",
"buyingPrice":1450.00,
"sellingPrice":2000.00
},
{
"partName":"brake",
"buyingPrice":50.00,
"sellingPrice":170.00
},
{
"partName":"wheel",
"buyingPrice":700.00,
"sellingPrice":750.00
}
]
}
]
Don't know what went wrong. Any help is appreciated. Thanks in advance.
I think that the easiest way to do that is with the following query using the positional operator $
db.getCollection('vehicles').updateMany({
"parts.partName": "brake",
"parts.sellingPrice": {
$lte: 170.00
}
},
{
"$set": {
"parts.$.sellingPrice": 500
}
})
In case you can use mongodb cursor methods like forEach try something like this.
After a few pipeline stages, I came up with following sample result which is one document. If the videos.views.userId contains 10, I need to indicate videos.isWatched = true else false. We can use $unwind, check the condition, then group it.
This is sample output, The original document contains a lot of field, so I just like to do with less code unless I need to unwind Is there any way to do without unwind("videos")?
[
{
"_id":"someId",
"videos":[
{
"_id":"1",
"name":"A",
"views":[
{
"userId":10,
"group":"X"
}
]
},
{
"_id":"2",
"name":"B",
"views":[
{
"userId":20,
"group":"Y"
}
]
}
],
"Assessment":[
{
"_id":"22",
"title": "Hello world"
}
]
}
]
Expected result
[
{
"_id":"someId",
"videos":[
{
_id:"1",
name:"A",
views:[
{
userId:10,
group:"X"
}
],
"isWatched":true
},
{
_id:"2",
name:"B",
views:[
{
userId:20,
group:"Y"
}
],
"isWatched":false
}
],
"Assessment":[
{
_id:"22",
title: "Hello world"
}
]
}
]
You can use $map along with $mergeObjects to add a new field to an existing array. $anyElementTrue can be used to determine whether there's any userId equal to 10:
db.collection.aggregate([
{
$addFields: {
videos: {
$map: {
input: "$videos",
in: {
$mergeObjects: [
"$$this",
{
isWatched: {
$anyElementTrue: {
$map: { input: "$$this.views", in: { $eq: [ "$$this.userId", 10 ] } }
}
}
}
]
}
}
}
}
}
])
Mongo Playground
Let's say I have a Purchase order document and this purchase order document has Ids of the supplier and outlet which both of them are separated document (*not embedded).
What I want when user query like this from client-side "give me the purchase order documents which (purchase-order reference-number or supplier name or outlet name) is like "Otilia"
The aggregation query I made so far is this:
[
{
"$lookup":{
"from":"outlets",
"localField":"outlet",
"foreignField":"_id",
"as":"outlets"
}
},
{
"$lookup":{
"from":"suppliers",
"localField":"supplier",
"foreignField":"_id",
"as":"suppliers"
}
},
{
"$match":{
"$and":[
{
"$or":[
{
"outlets.name":{
"$regex":".*Otilia.*",
"$options":"i"
},
"referenceNumber":{
"$regex":".*Otilia.*",
"$options":"i"
},
"suppliers.name":{
"$regex":".*Otilia.*",
"$options":"i"
}
}
]
}
]
}
},
{
"$sort":{
"outlets.name":1,
"_id":1
}
}
]
What is working:
if I remove the tow other objects from $or array which looks like this
[
{
"$lookup":{
"from":"outlets",
"localField":"outlet",
"foreignField":"_id",
"as":"outlets"
}
},
{
"$lookup":{
"from":"suppliers",
"localField":"supplier",
"foreignField":"_id",
"as":"suppliers"
}
},
{
"$match":{
"$and":[
{
"$or":[
{
"suppliers.name":{
"$regex":".*Otilia.*",
"$options":"i"
}
}
]
}
]
}
},
{
"$sort":{
"outlets.name":1,
"_id":1
}
}
]
Note: I used $and because it could be more filters from client-side like purchase order status and more.
Purchase Order document Sample
Supplier document Sample:
outlet document Sample:
The result I want t to achieve is the matched purchase orders documents by the query.
Solved by wrapping every $or expression with {}.
I just forgot to wrap every $or expression in brackets.
the correct format of the query is this:
[
{
"$lookup":{
"from":"outlets",
"localField":"outlet",
"foreignField":"_id",
"as":"outlets"
}
},
{
"$lookup":{
"from":"suppliers",
"localField":"supplier",
"foreignField":"_id",
"as":"suppliers"
}
},
{
"$match":{
"$and":[
{
"$or":[
{
"orderNumber":{
"$regex":".*Celia Pouros.*",
"$options":"i"
}
},
{
"supplierInvoice":{
"$regex":".*Celia Pouros.*",
"$options":"i"
}
},
{
"suppliers.name":{
"$regex":".*Celia Pouros.*",
"$options":"i"
}
}
]
}
]
}
},
{
"$sort":{
"outlets.name":1,
"_id":1
}
}
]
Below is my schema:
{
"_id":ObjectId("5c49c783de72ec2ec47b95d1"),
"placement":[
{
"offer":[
{
"sent_by":"John",
"comment":""
},
{
"sent_by":"Mary",
"comment":""
}
]
}
]
}
I want to update placement.offer.comment where placement.offer.sent_by is Mary but it always updates the first record. I don't want to provide a hard coded number like placement.0.offer.1.sent_by.
This should be the resulting document:
{
"_id":ObjectId("5c49c783de72ec2ec47b95d1"),
"placement":[
{
"offer":[
{
"sent_by":"John",
"comment":""
},
{
"sent_by":"Mary",
"comment":"Some comment updated"
}
]
}
]
}
You would need to use array filters to achieve that:
db.collection.update(
{ /* add additional query filters here */ },
{ $set: { "placement.$[].offer.$[o].comment": "Some updated comment" } },
{ arrayFilters: [ { "o.sent_by": "Mary" } ] }
)
Upon the mongoose find() query the result i am getting is:
[
{
"services":[
{
"location":[
17.4374614,
78.4482878
]
},
{
"location":[
17.4020637,
78.48400519999996
]
},
{
"location":[
17.387031788259197,
78.47838450137715
]
}
]
}
]
Is there any way to extract the output in such a way that i want an array of only location values such as:-
[
'17.4374614',
'78.4482878',
'17.4020637',
'78.48400519999996',
'17.387031788259197',
'78.47838450137715'
]
Edit: I am aware that map method does the job, but i am not able to find a workaround of implementing the map method for the above query.
My schema:
var serviceSchema = new mongoose.Schema({
location:[{type: Number}]
})
I used for-of loop and map function to achieve the result you need
var your_output =[
{
"services":[
{
"location":[
17.4374614,
78.4482878
]
},
{
"location":[
17.4020637,
78.48400519999996
]
},
{
"location":[
17.387031788259197,
78.47838450137715
]
}
]
}
]
var location_array = []
for (var services of output[0].services) {
for(var loc of services.location){
location_array.push(loc)
}
}
location_array.map(String)