This is my Conversation Schema
const ConversationSchema = new Schema({
recipients: [{ type: Schema.Types.ObjectId, ref : 'User' }],
lastMessage: {
type: String,
default: ''
},
date: {
type: Date,
default: Date.now()
},
})
I want to know if there exist an array [ patientId, doctorId ]
Here is my main approach to find
I am not able to get the response and I already have one document with that same array
const conversationBetween = await Conversation.findOne(
{
recipients: {
$all: [
{ $elemMatch: { $eq: patientId }},
{ $elemMatch: { $eq: doctorId }}
],
}
}
)
if (conversationBetween) {
return res.status(401).json({
status: "failed",
message: "You already have a conversation with this doctor"
});
}
following Code to add a Conversation in the Conversation Collection, this works fine
const newConversation = new Conversation({
recipients: [ patientId,doctorId ],
lastMessage: `I want to get consultation`,
date: Date.now(),
})
await newConversation.save()
res.status(200).json({
status: "success",
message: "Conversation added successfully",
conversation: newConversation
});
The main purpose is to make sure that if there present an entry with [ patientId, doctorId ] in Conversation it should not make a new entry..
But at this time its not able to find and is making that same entry.
You can do this
await Conversation.findOne(
{
recipients: [patientId, doctorId]
}
)
Working in Playground
Related
I am using findOneAndUpdate, where I want
to return updated document
i dont want to return the entire document but only the following:
one object out of an array + a virtual property in the document.
const notifications = {
to:
messages: [
{_id: "23452", title:"hello"}, {_id: "23452", title:"bye"}
]
...
}
so for example I would want to only return the object {_id: "23452", title:"bye"} AND unreadCount virtual field prop.
my code works so far as I am returning updated document and only the message I want, but I dont know how to return also the unreadCount prop.
schema:
const notificationSchema = new mongoose.Schema({
to: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
messages: [{
title: {
type: String,
required: true
},
isRead: {
type: Boolean,
default: false
},
createdAt: {
type: Date,
default: new Date()
}
}, ]
},
{timestamps: true, toObject: {virtuals: true}
});
notificationSchema.virtual('unreadCount').get(function() {
... return count;...
})
updateRead: async (userId, id) => {
const notification = await Notification.findOneAndUpdate({to: userId, 'messages._id': id}, {
$set: { "messages.$.isRead": true} },
{ select: {
messages: {
$elemMatch: {_id: id}
}
}, new: true});
}
I am new to mongoDb. I have created a collection named task that has comments field which is array along with other fields. I need to edit specific comment of the task. There is a edit button in each comment. Both task id and comment id are available. Now how to edit specific comment of the task?
Thanks in advance
task api
{
"status":true,
"task":[
{
"_id":"61dfef323a6ee474c4eba926",
"description":"hello there",
"title":"hello",
"comments":[
{
"comment_id":1,
"username":"test",
"comment":"abcd",
"status":true,
},
{
"comment_id":2,
"username":"test",
"comment":"abcdsdfsdf",
"status":true,
}
],
"createdAt":"2022-01-13T09:21:54.795Z",
"updatedAt":"2022-01-13T09:21:54.795Z",
"__v":0
}
]
}
Task model schema
const taskSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
comments: [Object],
}, {
timestamps: true,
});
I tried using $set but I don't know how to use it in the inner array.
router.route('./comments/edit').post((req, res) => {
const commentId = req.body.commentId;
const taskId = req.body.postId;
const comment = req.body.editedComment;
const updatedAt = new Date();
Task.updateOne(
{ _id: taskId},
{
//what to do here?
// $set: { comments: [ {'comment_id': commentId} ]},
}
)
.then((response) => res.json({ status: true, msg: 'Comment Edited!' }))
.catch(err => res.json({ status: false, msg: err }));
});
Thanks in advance.
This is how to do best:
db.collection.update({
status: true
},
{
$set: {
"task.$[x].comments.$[y].username": "New Name"
}
},
{
arrayFilters: [
{
"x._id": "61dfef323a6ee474c4eba926"
},
{
"y.comment_id": 2
}
]
})
Explained:
Define x and y as arrayFIlters in the update statement.
In the $set statement provide the x & y filters to identify the specific comment for update.
In the example I update the username , but you can update any other value from the targeted array subelement addressed by x & y.
playground
And here is how to update two values at same time in the same nested array element.
I have some simple user data. Here is example for one user:
const userSchema = new Schema({
userName: {
type: String,
},
projectsInput: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
projectsHold: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
});
I want by having ProjectId to be able to remove all records from all users that contains it.
if I get the first one
60f02d21159c4b4110f21a32
how I can perform updateMany function for my UserModel?
return UserModel.updateMany(
{
projectsInput: {
$elemMatch: args.projectId,
},
},
{
projectsInput: {
$slice: [projectsInput.$, 1],
},
}
);
})
Here is my code that is not working.
args.projectId = 60f02d21159c4b4110f21a32 (my id for the project I want to delete)
and UserModel is my mongodb Schema for user.
you can use $pull
{
$pull: {
projectsInputs: "123"
}
}
I'm trying to make a discover page for a social media website. The discover page queries the database for all posts that satisfy four things:
User has not already liked post
Post tags do not violate user's filtered tag content
Post text content does not violate user's filtered post content
And finally the part of the aggregation giving me trouble:
Post tagIds contain a given tagId from user (a post using the same tag that the user already follows)
Here's the function:
const asyncFetchTagPosts = async (
query,
//here's a given tag that a user already follows
tagId,
likedPostIds,
Post,
User,
mongoose,
handleFilterTagRegex,
handleFilterPostContentRegex
) => {
var recastTagId = mongoose.Types.ObjectId(tagId)
var user = await User.findOne({ blogName: query })
var filteredTagRegex = handleFilterTagRegex(user)
var filteredPostContentRegex = handleFilterPostContentRegex(user)
var posts = await Post.aggregate([
{
$lookup: {
from: 'posts',
let: {
likedPostIds: likedPostIds,
tagId: recastTagId,
filteredTagRegex: filteredTagRegex,
filteredPostContentRegex: filteredPostContentRegex
},
pipeline: [
{
$match: {
$expr: {
$and: [
{ $not: { $in: ["$_id", "$$likedPostIds"] } },
{ $not: [
{
$regexMatch: {
input: "$tagTitles",
regex: "$$filteredTagRegex"
}
}
]
},
{ $not: [
{
$regexMatch: {
input: "$allText",
regex: "$$filteredPostContentRegex"
}
}
]
},
{ $or: [
//here's the bad expression, $tagIds won't resolve to an array
{ $in: [ "$$tagId", "$tagIds" ] },
]
}
]
}
}
}
],
as: 'posts'
}
},
{ $unwind: '$posts' },
{ $replaceRoot: { "newRoot": "$posts" } },
{ $sort: { "notesHeatLastTwoDays": -1 } },
{ $limit: 5 }
])
return posts
}
Here's the Post model:
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const options = { discriminatorKey: 'kind' }
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
allText: {
type: String
},
descriptions: [
{
kind: String,
content: String,
displayIdx: Number
}
],
descriptionImages: [
{
type: Schema.Types.ObjectId,
ref: 'Image'
}
],
tagIds: [
{
type: Schema.Types.ObjectId,
ref: 'Tag'
}
],
tagTitles: {
type: String
},
mentions: [
{
type: Schema.Types.ObjectId,
ref: 'Mention'
}
],
notesCount: {
type: Number,
default: 0
},
notesHeatLastTwoDays: {
type: Number,
default: 0
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
},
kind: {
type: String,
default: 'Post'
}
}, options)
const Post = mongoose.model('Post', PostSchema, 'posts')
export default Post;
I keep getting this error:
Error: $in requires an array as a second argument, found: missing
When I comment out the last part of the query the aggregation works. It returns data in this shape:
{
_id: 60c18ee43730198901cfae9b,
descriptionImages: [],
//here's the array I'm trying to get to resolve in the aggregation
tagIds: [],
mentions: [],
notesCount: 1,
notesHeatLastTwoDays: 0,
kind: 'VideoPost',
descriptions: [],
createdAt: 2021-06-10T04:02:44.744Z,
updatedAt: 2021-06-11T08:51:38.166Z,
user: 608f213bb4a094bd91e02936,
videoLink: 60c3241a6c9ed4d1fc908270,
allText: '',
__v: 1,
tagTitles: ''
},
I thought using the $ operator in the aggregation gave me access to each document, does it just not work if you try to use the variable as the first expression?
you need to handle missing "$tagIds" by setting it to empty array []
{
$ifNull: [
"$tagIds",
[]
]
}
https://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/
so you pipeline stage would be
{ $or: [
//here's the bad expression, $tagIds won't resolve to an array
{ $in: [ "$$tagId", { $ifNull: [ "$tagIds", [] ] } ] },
]
}
I currently have the the collection "Plans" and it is made upon the creation of a form submit. It inserts the following:
Plans.insert({
location,
address,
date,
time,
notes,
createdAt: new Date(), // current time
owner: Meteor.userId(),
username: Meteor.user().username,
attendees: [
{
attender: [{
user: String,
attending: Boolean,
}],
},
],
});
Then, upon a click of a checkbox, I want a new attender object to be added to the attendees array. So far I have tried to do:
'click .notattending'() {
Plans.insert(
{_id: this._id,
attendees: [{
attender: [
{
user: Meteor.user().username,
attending: false,
}
],
}
]
},
);
},
However it isn't adding to the Mongo collection. Is this the correct way to go about doing it?
You can try this to based on your schema.
Plans.update({ _id: this._id }, {
$push: {
attendees: { user: "", attending: true },
},
});