how to find item in collection with $match - node.js

I have collection trusted contacts. I need to filter the document by the user. When I use method findOne I have a result, but when I use $match I got an empty array. I don't know why $match doesn't work for me.
Collection trusted contacts:
{
"_id": {
"$oid": "5d76008e4b98e63e58cb34cc"
},
"date": {
"$date": "2019-09-09T07:32:20.174Z"
},
"approvedTrustedContacts": [
{
"_id": {
"$oid": "5d764e411b7476462cf6b540"
},
"user": {
"$oid": "5c5ecaf6134fc342d4b1a9d5"
}
},
{
"_id": {
"$oid": "5d7750af52352918f802c474"
},
"user": {
"$oid": "5c64968cae53a8202c963223"
}
}
],
"pendingApprovalContacts": [],
"waitingForApprovalContacts": [],
"user": {
"$oid": "5d76008e4b98e63e58cb34cb"
}
},
{
"_id": {
"$oid": "5d7605f5e7179a084efa385b"
},
"date": {
"$date": "2019-09-09T07:32:20.174Z"
},
"approvedTrustedContacts": [
{
"_id": {
"$oid": "5d764e411b7476462cf6b541"
},
"user": {
"$oid": "5d76008e4b98e63e58cb34cb"
}
}
],
"pendingApprovalContacts": [],
"waitingForApprovalContacts": [],
"user": {
"$oid": "5c5ecaf6134fc342d4b1a9d5"
}
}
when I use method findOne
const user = await TrustedContacts.findOne({ user: "5d76008e4b98e63e58cb34cb" })
I have result
but when I use $match I got empty array
result1 = await TrustedContacts.aggregate([
{ $match: { user: "5d76008e4b98e63e58cb34cb" } },
]);

It Works,
const ObjectId = require('mongodb').ObjectId;
result1 = await TrustedContacts.aggregate([
{ $match: { user: ObjectId("5d76008e4b98e63e58cb34cb") } },
]);

Related

fetch array based length - mongoose

I have visitors array. Based on length I want to fetch first 40(highest visted) videos. Is there any query in mongoose for this?
"videos": [],
"description": "Runs for indai",
"status": 1,
"_id": "5e68ee512d3fe53a4426fea5",
"likes": [],
"visited": [{
"_id": "5e690d28797f5b05e066104d",
"user": "::1"
},
{
"_id": "5e690d14797f5b05e066104c",
"user": "::1"
},
{
"_id": "5e690cf7797f5b05e066104b",
"user": "::1"
}],
"comments": [],
"embed": "https://wwdalkfa.com/idaa/46221",
"category": "Mathrubhumi",
"title": "Bdis idnc - Aria.",
"link": "https://www.mdaoa.com/video/46221/dafa",
"image": "https://www.mdaoa.com/media/videos/dstmb1/46221/1b.jpg",
"keywords": "adjal","DAfa",
"__v": 0
controller
exports.getTrendingVideos = async (req, res) => {
try {
const videos = await Video.find().limit(40);
res.send(videos);
} catch (error) {}
};
First, get the length of the array and then sort it, You can do it like this
const videos = await Video.aggregate([
{ $project: { visitedCount: { $size: '$visited' } } },
{ $sort: { $visitedCount: -1 } },
]).limit(40);

MongoDB push into nested array

I have this scheme
{
"_id": {
"$oid": "5e187b1791c51b4b105fcff0"
},
"username": "test",
"email": "test#test.com",
"role": "admin",
"userScoreFantasy": {
"tournaments": [
{
"tournament_id": {
"$oid": "5e1892fb480f344830a3f160"
},
"predictions": [],
"score": null
},
{
"tournament_id": {
"$oid": "5e189f5f8d88292754e10b37"
},
"predictions": [],
"score": null
}
],
"totalScore": null
},
}
I want to do this :
Find user with a predefined user id
Pass all userScoreFantasy.tournaments array to find a specific tournament id
Push into the found tournament predictions array an object like this one :
{
score,
"match_id": foundMatch._id
}
So the tournaments array will become :
[
{
"tournament_id": {
"$oid": "5e1892fb480f344830a3f160"
},
"predictions": [
"score" : 200,
"match_id": "5e1892fb480f34faw21410"
],
"score": null
},
]
I tried to do this :
Users.update({
"_id": prediction.user_id,
"userScoreFantasy.tournaments": {
"$elemMatch": {
"tournament_id": foundMatch.tournament_id
}
}
}, {
"$push": {
"userScoreFantasy.tournaments.$.predictions": {
score,
"match_id": foundMatch._id
}
}
})
But the array is not updating.
EDIT :
Working call :
Users.updateOne({
"_id": ObjectID(prediction.user_id),
}, {
$addToSet: {
"userScoreFantasy.tournaments.$[element].predictions": {
score,
"match_id": foundMatch._id
}
}
}, {
arrayFilters: [{
"element.tournament_id": ObjectID(foundMatch.tournament_id)
}]
}
)
You should use the position indentifier to update your arrays, like so:
Users.updateOne(
{
"_id": prediction.user_id,
},
{
$addToSet: {
"userScoreFantasy.tournaments.$[element].predictions": {
score,
"match_id": foundMatch._id
}
}
},
{arrayFilters: [{"element.tournament_id": foundMatch.tournament_id}]}
);

Find and remove by Id a subdocument in array with mongoose

I'm trying to delete a subdocuments in array with Mongoose.
My datas :
{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb762"
},
"spaces": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76f"
},
"name": "Building 2",
"subSpace": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb771"
},
"name": "Basement"
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb770"
},
"name": "Floors"
}]
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76c"
},
"name": "Building 4",
"subSpace": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76e"
},
"name": "Basement"
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76d"
},
"name": "Floors"
}]
}]
}
For this example, we want to delete the subSpace Floors in Building 2 with this _id : 5d88dfe45feb4c06a5cfb771
My code (in the model) :
exports.removeSubSpaceById = (subSpaceId) => {
Residence.findOneAndUpdate( { "spaces.subSpace._id": '5d88dfe45feb4c06a5cfb771' },
{ $pull:
{ spaces:
{ subSpace:
{ _id: '5d88dfe45feb4c06a5cfb771' }}}}, function(err, result) {
console.log(result);
})
};
Output : console.log : my entire document
But the subSpace/Basement (5d88dfe45feb4c06a5cfb771) is still in my document.
Thanks for your help.
Use positional operator for nested array operations. MongoDb Docs
exports.removeSubSpaceById = (subSpaceId) => {
Residence.findOneAndUpdate({ "spaces._id": '5d88dfe45feb4c06a5cfb76f' },
{
$pull:
{
"spaces.$.subSpace": { _id: "5d88dfe45feb4c06a5cfb771" }
}
}, function (err, result) {
console.log(result);
})
}

mongoose 4.7.5: how to fetch subdocuments in array

Am trying to fetch and filter subdocuments in array.
The document has this structure:
{
"_id": {
"$oid": "58bc4fa0fd85f439ee3ce716"
},
"updatedAt": {
"$date": "2017-03-08T20:39:19.390Z"
},
"createdAt": {
"$date": "2017-03-05T17:49:20.455Z"
},
"app": {
"$oid": "58ae10852035431d5a746cbd"
},
"stats": [
{
"meta": {
"key": "value",
"key": "value"
},
"_id": {
"$oid": "58bc4fc4fd85f439ee3ce718"
},
"data": "data",
"updatedAt": {
"$date": "2017-03-05T17:49:56.305Z"
},
"createdAt": {
"$date": "2017-03-05T17:49:56.305Z"
}
},
{
"meta": {
"key": "value",
"key": "value"
},
"_id": {
"$oid": "58c06bf79eaf1f15aafe39d0"
},
"data": "data",
"updatedAt": {
"$date": "2017-03-08T20:39:19.391Z"
},
"createdAt": {
"$date": "2017-03-08T20:39:19.391Z"
}
}
]
}
What i want to get is the subdocuments in the stats array between two dates
I tried mongoose queries chain:
Model.findById(id)
.select('stats')
.where('stats.createdAt').gt(data-value).lt(data-value)
But the result always the full document including the all the subdocuments.
Also I tried aggregation like this:
Model.aggregate({
$match: {
'stats.createdAt': '2017-03-05T17:49:56.305Z'
}
})
The result is always null
Your result is null because '2017-03-05T17:49:56.305Z' is a String, you are looking for a Date : new Date('2017-03-05T17:49:56.305Z')
You can filter subdocuments with a date range with $unwind and $match :
var startDate = new Date('2017-03-05T17:49:56.305Z');
var endDate = new Date('2017-03-08T17:49:56.305Z');
Model.aggregate([{
$match: {
"_id": new mongoose.mongo.ObjectId("58bc4fa0fd85f439ee3ce716"),
"stats.createdAt": {
$gte: startDate,
$lt: endDate
}
}
}, {
$unwind: "$stats"
}, {
$match: {
"stats.createdAt": {
$gte: startDate,
$lt: endDate
}
}
}], function(err, res) {
console.log(res);
})
Or more straightforward with $filter :
Model.aggregate([{
$match: {
"_id": new mongoose.mongo.ObjectId("58bc4fa0fd85f439ee3ce716"),
"stats.createdAt": {
$gte: startDate,
$lt: endDate
}
}
}, {
$project: {
"stats": {
$filter: {
input: "$stats",
as: "stat",
cond: {
$and: [
{ $gte: ["$$stat.createdAt", startDate] },
{ $lte: ["$$stat.createdAt", endDate)] }
]
}
}
}
}
}], function(err, res) {
console.log(res);
})

Mongoose how to select certain object in embedded array

I had been searching around and still not able to find the correct answer.
Basically I have the below data model in mongodb
{
"_id": {
"$oid": "565db83bcd7bef020b1bdae8"
},
"userId": {
"$oid": "5653a3267827f178214918fc"
},
"targetUser": [
{
"userId": {
"$oid": "564663a5c0aefc151625b5e2"
},
"status": "Approved",
"_id": {
"$oid": "565db83bcd7bef020b1bdaea"
}
},
{
"userId": {
"$oid": "564548249bb75c600ff94cdd"
},
"status": "Sent",
"_id": {
"$oid": "565db884cd7bef020b1bdaed"
}
}
]
},
{
"_id": {
"$oid": "565db884cd7bef020b1bdaec"
},
"userId": {
"$oid": "564548249bb75c600ff94cdd"
},
"targetUser": [
{
"userId": {
"$oid": "5653a3267827f178214918fc"
},
"status": "Pending",
"_id": {
"$oid": "565db884cd7bef020b1bdaee"
}
}
]
}
How can I only return the follow data???
{
"userId": {
"$oid": "5653a3267827f178214918fc"
},
"targetUser": [
{
"userId": {
"$oid": "564663a5c0aefc151625b5e2"
},
"status": "Approved",
"_id": {
"$oid": "565db83bcd7bef020b1bdaea"
}
},
}
I had use the below code, but the result is return null
Connection.aggregate([
{$match:{userId:'5653a3267827f178214918fc'}},
{$unwind:'$targetUser'},
{$match:{'targetUser.status':'Approved'}},
{$group:{
_id:'$_id',
targetUser:{
$push:{
status:'$targetUser.status'
}
}
}}
],function(err,connections){
console.log(connections);
console.log(err);
})
Thank you so much for the help
From what I see, you don't need to aggregate, a simple find with a projection parameter will return what you need.
Connection.findOne({
userId: new ObjectId("5653a3267827f178214918fc")
}).select({
targetUser: {
$elemMatch: { status: "Approved" }
}
}).exec(callback);
But if you have more fields than userId and targetUser, you'll need to add them in the second parameter like this
Connection.findOne({
userId: new ObjectId("5653a3267827f178214918fc")
}).select({
targetUser: {
$elemMatch: { status: "Approved" }
},
oneMoreField: 1,
anotherField: 1
}).exec(callback);

Resources