How to pass in conditional values to query in MongoDB? - mongodb

I am new to MongoDB. I am having trouble writing filter logic for the following. Would you be so kind to help me out. =>
If isNightParty:true, check in DB for isNightParty Allowed:true and return all documents else Do Not Check
Here is my code:
router.get("/hotelList", (req,res) =>{
const {date, boys, girls, isNightParty} = req.body
businessUser.find(
{
$and:[
{isBlockedOn:{$ne:date}},
//{girlsWithBoys:isGirlsWithBoys},
{"isNightPartyAllowed":{$exists:true}}
}
).then((toListHotels)=>{
return (res.status(200).json(toListHotels))
})
.catch((err)=>{
console.log(err)
})
})
My DB structure is as follows:
{
"_id": {
"$oid": "6182603cce3b3b92991fee96"
},
"hotelName": "Hotel",
"email": "hotel1#hotel.com",
"password": "$2a$12$RXr2xTbnGP2ASUTqP2ptQOtS36QOr0.uq/OHTuIRLigYUM..T3lb6",
"location": "url",
"address": "address",
"isNightPartyAllowed": true,
"girlsWithBoys": true,
"roomSmallData": {
"smallPrice": "1000",
"smallPic": "url",
"smallCapacity": {
"$numberInt": "5"
},
"_id": {
"$oid": "6182603cce3b3b92991fee97"
}
},
"roomMediumData": {
"mediumPrice": "2000",
"mediumPic": "url",
"mediumCapacity": {
"$numberInt": "7"
},
"_id": {
"$oid": "6182603cce3b3b92991fee98"
}
},
"roomLargeData": {
"largePrice": "3000",
"largePic": "url",
"largeCapacity": {
"$numberInt": "10"
},
"_id": {
"$oid": "6182603cce3b3b92991fee99"
}
},
"__v": {
"$numberInt": "0"
},
"isBlockedOn": [
"Fri Nov 05 2021 00:00:00 GMT+0530 (India Standard Time)"
]
}

Use a $or to cater the 2 conditions:
input isNightParty is null
isNightPartyAllowed is true
either case should allow the documents to be returned
db.collection.aggregate([
{
$match: {
$expr: {
$or: [
// put your parameter <isNightParty> here
{
$eq: [
null,
<isNightParty>
]
},
{
$eq: [
{
"$ifNull": [
"$isNightPartyAllowed",
false
]
},
true
]
}
]
}
}
}
])
Here is the Mongo playground for your reference.

Related

MongoDB: Cannot increment with non-numeric argument

I have a collection of User documents, containing several fields and an array of Bets. I am trying to set up an update that I will run on a schedule. In the User documents, the Balance field needs to be incremented by (Bets[index].multiplier * Bets[index].amount), and the Bets[index] needs to be marked as paid out and whether the bet was successful.
An example of a User document I'm trying to update. After running the update, User.bets[1].isPaidOut should be true, User.bets[1].didWin should be true, and User.balance should be incremented by 89 (that is, because ceiling(1.27 * 70) = 89).
{
"_id": {
"$oid": "63c9ca0217b00eaef7d6237f"
},
"guildId": "1061387401743831121",
"userId": "307884715677974530",
"userName": "Iron Man",
"balance": {
"$numberDouble": "100.0"
},
"lastClaimedAt": {
"$date": {
"$numberLong": "1674168834621"
}
},
"bets": [
{
"sport": "NFL",
"eventWeek": {
"$numberInt": "2"
},
"team": "New York Giants",
"opponentTeam": "Philadelphia Eagles",
"teamId": {
"$numberInt": "19"
},
"opponentTeamId": {
"$numberInt": "21"
},
"eventId": "401438004",
"amount": {
"$numberInt": "20"
},
"multiplier": {
"$numberDouble": "3.85"
},
"isPaidOut": true,
"didWin": false
},
{
"sport": "NFL",
"eventWeek": {
"$numberInt": "2"
},
"team": "Philadelphia Eagles",
"opponentTeam": "New York Giants",
"teamId": {
"$numberInt": "21"
},
"opponentTeamId": {
"$numberInt": "19"
},
"eventId": "401438004",
"amount": {
"$numberInt": "70"
},
"multiplier": {
"$numberDouble": "1.27"
},
"isPaidOut": false
},
{
"sport": "NFL",
"eventWeek": {
"$numberInt": "2"
},
"team": "San Francisco 49ers",
"opponentTeam": "Dallas Cowboys",
"teamId": {
"$numberInt": "25"
},
"opponentTeamId": {
"$numberInt": "6"
},
"eventId": "401438006",
"amount": {
"$numberInt": "200"
},
"multiplier": {
"$numberDouble": "1.49"
},
"isPaidOut": false
}
],
"createdAt": {
"$date": {
"$numberLong": "1674168834633"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1674338378566"
}
},
"__v": {
"$numberInt": "3"
}
}
This is what I have for my Update. When this is run, I receive this error: uncaught promise rejection: write exception: write errors: [Cannot increment with non-numeric argument: {balance: { $ceil: { $mul: [ "bets.$.amount", "bets.$.multiplier" ] } }}]. I thought this could have been because of mismatched types, but all documents have the same as the one above.
const winnerId = 21;
const eventId = "401438004";
usersCollection.updateMany(
{
bets: {
"$elemMatch": {
eventId: eventId,
isPaidOut: false,
teamId: winnerId
}
}
},
{
$set: { "bets.$.isPaidOut" : true, "bets.$.didWin": true },
$inc: {
balance: {$ceil: {$mul: {"bets.$.amount": "bets.$.multiplier"} }}
}
}
);
$ceil is an aggregation operator, not an update operator, so you can only use it with an update if you use the update with aggregation pipeline
You will have to use pipelined update. But then, you won't be able to use $ field names. Here's a solution using $map and $reduce.
db.collection.updateMany(
bets: {
"$elemMatch": {
eventId: "401438004",isPaidOut: false,teamId: 21
}
},
[
{
"$set": {
"balance": { //set the updated balance
$reduce: {
input: "$bets", //iterate through the bets array
initialValue: "$balance", //start with the existing balance
in: {
$add: [
"$$value",
{
$cond: [ //check the condition
{$and: [
{$eq: ["$$this.eventId","401438004"]},
{$eq: ["$$this.teamId",21]},
{$eq: ["$$this.isPaidOut",false]}
]},
{$ceil: {$multiply: ["$$this.amount","$$this.multiplier"]}}, //if true, perform the arithmetic operation andd add it to existing $$value
0 //if false, add 0
]
}
]
}
}
},
"bets": { //set the updated bets array
$map: { //iterate through the bets array
input: "$bets",
in: {
$cond: [ //check the condition
{$and: [
{$eq: ["$$this.eventId","401438004"]},
{$eq: ["$$this.teamId",21]},
{$eq: ["$$this.isPaidOut",false]}
]},
{
"$mergeObjects": [ //if true, merge the array element with updated fields
"$$this",
{"didWin": true,"isPaidOut": true}
]
},
{
"$mergeObjects": [ //if false, keep the array element as it is
"$$this"
]
}
]
}
}
}
}
}
])
Demo

unable to update a subdocuments in an array

im trying to update a value for uid in solts.slots but nothing works.
i want to iterate two level of array to modify the document
{
"_id": {
"$oid": "638455dee12f0122c9812697"
},
"bid": "637b0fdd3d9a96eb913805d3",
"name": "sucess",
"slots": [
{
"date": "2022-11-28T00:00:00.000Z",
"slots": [
{
"uid": null,
"available": true,
"status": null,
"_id": {
"$oid": "638455dee12f0122c98126a0"
}
},
{
"uid": null,
"available": true,
"status": null,
"_id": {
"$oid": "638455dee12f0122c98126a1"
}
}
],
"_id": {
"$oid": "638455dee12f0122c9812698"
}
}
]}]}
im trying to update the slots for id 638455dee12f0122c98126a0 properties like
uid:'234235'
available:false
status:'booked'
can anyone help me to query this
i tried
const result = await Event.findOne({
'slots.slots': {
$elemMatch: {
_id: req.body.id
}
}
})
is there is any way to query this type of documents.
You can use $[] and $[<identifier>]:
db.collection.update({
"slots.slots": {
$elemMatch: {
_id: ObjectId("638455dee12f0122c98126a0")
}
}
},
{
$set: {
"slots.$[].slots.$[item].available": false,
"slots.$[].slots.$[item].uid": "234235",
"slots.$[].slots.$[item].status": "booked"
}
},
{
arrayFilters: [
{
"item._id": ObjectId("638455dee12f0122c98126a0")
}
]
})
See how it works on the playground example

need to phonenumber from table abc in mongodb

{
"id": "1234",
"applicant": [
{
"phone": [
{
"prirotynumber": "1",
"areacode": "407",
"linenumber": "1234",
"exchangenumber": "7899"
},
{
"prirotynumber": "27",
"areacode": "407",
"linenumber": "1234",
"exchangenumber": "79999"
}
]
}
]
}
for this id=1234 i need to fetch homephonenuber as applicant.phone.areacode+applicant.phone+linenumber+ applicant.phone+exchangenumber if prirotynumber=1
and
cellphone as applicant.phone.areacode+applicant.phone+linenumber+ applicant.phone+exchangenumber if prirotynumber=27
Expected result here:
{
"key":"value"
}
If this isn't what you need, make your expected result more clarify with right sample data.
db.collection.aggregate([
{
"$match": {
"id": "1234",
"applicant.phone.prirotynumber": "1"
}
},
{
"$unwind": "$applicant"
},
{
"$unwind": "$applicant.phone"
},
{
"$match": {
"applicant.phone.prirotynumber": "1"
}
},
{
"$set": {
"homePhoneNumber ": {
$concat: [
"$applicant.phone.areacode",
"-",
"$applicant.phone.linenumber",
"-",
"$applicant.phone.exchangenumber"
]
}
}
}
])
mongoplayground

Filter documents that have id in another collection in MongoDB with aggregation framework

So I have two collection. collectionA and collectionB
collection A has following documents
db={
"collectiona": [
{
"_id": "6173ddf33ed09368a094e68a",
"title": "a"
},
{
"_id": "61wefdf33ed09368a094e6dc",
"title": "b"
},
{
"_id": "61wefdfewf09368a094ezzz",
"title": "c"
},
],
"collectionb": [
{
"_id": "6173ddf33ed0wef368a094zq",
"collectionaID": "6173ddf33ed09368a094e68a",
"data": [
{
"userID": "123",
"visibility": false,
"response": false
},
{
"userID": "2345",
"visibility": true,
"response": true
}
]
},
{
"_id": "6173ddf33ed09368awef4e68g",
"collectionaID": "61wefdf33ed09368a094e6dc",
"data": [
{
"userID": "5678",
"visibility": false,
"response": false
},
{
"userID": "674",
"visibility": true,
"response": false
}
]
}
]
}
So What I need is documents from collection A which has response false in collection B
and document should be sorted by first the ones that have visibility false and then the ones that have visibility true
for eg. userID : 123 should get 3 documents
{
"_id": "6173ddf33ed09368a094e68a",
"title": "a"
},
{
"_id": "61wefdf33ed09368a094e6dc",
"title": "b"
},
{
"_id": "61wefdfewf09368a094ezzz",
"title": "c"
},
whereas userID 2345 should get two
{
"_id": "61wefdf33ed09368a094e6dc",
"title": "b"
},
{
"_id": "61wefdfewf09368a094ezzz",
"title": "c"
},
User 674 will receive 3 objects from collection A but second would be in the last as it has visibility true for that document
{
"_id": "6173ddf33ed09368a094e68a",
"title": "a"
},
{
"_id": "61wefdfewf09368a094ezzz",
"title": "c"
},
{
"_id": "61wefdf33ed09368a094e6dc",
"title": "b"
},
MongoDB Playground link : https://mongoplayground.net/p/3rLry0FPlw-
Really appreciate the help. Thanks
You can start from collectionA:
$lookup the collectionB for the record related to the user specified
filter out collectionB documents according to response
assign a helper sortrank field based on the visibility and whether collectionaID is a match
$sort according to sortrank
wrangle back to the raw collection A
db.collectiona.aggregate([
{
"$lookup": {
"from": "collectionb",
let: {
aid: "$_id"
},
"pipeline": [
{
$unwind: "$data"
},
{
$match: {
$expr: {
$and: [
{
$eq: [
"$data.userID",
"2345"
]
},
{
$eq: [
"$collectionaID",
"$$aid"
]
}
]
}
}
}
],
"as": "collB"
}
},
{
$match: {
"collB.data.response": {
$ne: true
}
}
},
{
"$unwind": {
path: "$collB",
preserveNullAndEmptyArrays: true
}
},
{
"$addFields": {
"sortrank": {
"$cond": {
"if": {
$eq: [
"$collB.data.visibility",
false
]
},
"then": 1,
"else": {
"$cond": {
"if": {
$eq: [
"$collB.collectionaID",
"$_id"
]
},
"then": 3,
"else": 2
}
}
}
}
}
},
{
$sort: {
sortrank: 1
}
},
{
$project: {
collB: false,
sortrank: false
}
}
])
Here is the Mongo playground for your reference.

Mongoose - Search an array and return the matched results

I am looking for a way to return matched items under an array in Mongo (mongoose).
The data structure is like this:
[
{
"_id": {
"$oid": "123456"
},
"make": "Lamborghini",
"makeLogo": "/images/makeLogos/lamborghini.png",
"models": [
{
"model": "Aventador",
"_id": {
"$oid": "678909t"
}
},
{
"model": "Countach",
"_id": {
"$oid": "678909"
}
}
],
"__v": 0
},
{
"_id": {
"$oid": "2345678i90"
},
"make": "Nissan",
"makeLogo": "/images/makeLogos/nissan.png",
"models": [
{
"model": "350z",
"_id": {
"$oid": "678909gggg"
}
},
{
"model": "370z",
"_id": {
"$oid": "678909rrrrr"
}
}
],
"__v": 0
}
]
I would like to search: 3 and it should return 350z and 370z to me.
I tried the below:
modelsModel.find(
{"models.model": { $regex: req.query.carModel + '.*', $options:'i'}},
)
.exec(function(err, models) {
if(err){
res.status(400).json({error: err});
} else {
res.status(200).json({cars: models});
}
});
Where the data returned is this:
[
{ _id: 5ca893b7587ab519613b806e,
make: 'Lamborghini',
makeLogo: '/images/makeLogos/lamborghini.png',
__v: 0,
models: [
[Object], [Object]
]
}
]
This is when I searched for Countach which has a match.
I know I am doing something very obviously wrong here but this is so new to me I don't even know where to begin.
Thanks in advance!
You can use below aggregation with mongodb 4.2
db.collection.aggregate([
{ "$match": {
"models.model": { "$regex": "A" }
}},
{ "$project": {
"models": {
"$filter": {
"input": "$models",
"cond": {
"$regexMatch": {
"input": "$$this.model",
"regex": "A"
}
}
}
}
}}
])