I am trying to make a query to find documents depending on another document in the same collection as below.
The first one finds the user and the second one finds the data by using that user data received. But I want to do it with one query like join in SQL
This is schema
var ConnectionSchema = new Schema({
socketId: {
type: String,
require: true
},
location: {
type: [Number],
index: '2dsphere'
},
user: { type: Schema.ObjectId, ref: "User" },
date: {
type: Date,
require: true,
default: new Date()
}
});
// queries
return mongoose.model("Connection").findOne({ user: userId }).populate("user").then(usr => {
return mongoose.model("Connection").find({
location: {
$near: {
$maxDistance: config.searchDistance,
$geometry: { type: Number, coordinates: usr.location }
}
},
user: { $ne: userId },
});
});
Is there any way to do that with a just single query?
Thanks.
yes there is a way you can do like this
return mongoose.model("Connection").findOne({ user: userId })
.populate("user" ,
match : {$and : [{location: {
$near: {
$maxDistance: config.searchDistance,
$geometry: { type: Number, coordinates: usr.location }
}
}},
{user: { $ne: userId }}]})
.then(usr => {
// perform your action
});
Related
I have a user schema and each user have a profile in which he has a collection of book, and the user wants to remove a single book from the bookCollection, I have tried my code is at the bottom. The user schema is as follows:
var bookSchema = new Schema({
title: {
type: String,
required: true,
},
author: {
type: String,
required: true,
},
publisher: {
type: String,
default: "not set"
},
desc: {
type: String,
default: "not set"
},
availableAs: {
type: String, //either hardcopy or softcopy
required: true
},
price: {
type: Number,
default: 0
},
category: {
type: String,
default: "not set"
},
imageurl: {
type: String,
default: 'nobook.png'
},
bookurl: {
type: String,
default: ''
},
softcopy_available: {
type: Number,
default: 0
}
});
var userSchema = new Schema({
admin: {
type: Boolean,
default: false
},
bookCollection: [bookSchema]
});
This is what I am trying, but deletion is not working, sometimes it shows error and the page keeps on loading.
router.post('/', (req, res, next) => {
console.log(req.body.bookid);
var id=req.body.bookid;
users.findOne({
})
.then((user1) =>
user1.bookCollection.pull(req.body.bookid._id);
})
.catch((err) => {
next(err)
});
});
Why don't you use updateOne, or UpdateMany to pull the book from bookcollection, if you need to remove from a single user
var ObjectId = mongoose.Types.ObjectId;
users.updateOne({_id: ObjectId(user_id)},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});
If want to remove a certain book from all the users
var ObjectId = mongoose.Types.ObjectId;
users.updateMany({},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});
Here is my schema by using mongoose npm package.
var StatusSchema = new mongoose.Schema({
empName: {
projectName: { type: String },
clientName: { type: String },
statusLastWeek: { type: String },
statusThisweek: { type: String },
planNextWeek: { type: String }
}
});
Here is my nodejs code to update the data
var Status = mongoose.model('Status', StatusSchema);
module.exports = Status;
Description: Want save data in MongoDB, data schema is like above mentioned,
save saving data is sored loke as bellow.
Inside Mongo DB :
{ "_id" : ObjectId("5d92f4aba4695e2dd90ab438"), "__v" : 0 }
{ "_id" : ObjectId("5d92f4b4a4695e2dd90ab439"), "__v" : 0 }
Expected collection in MongoDB :
Dave Smith {
projectName: BLE Mesh,
clientName: Tera,
statusLastWeek: BLE Scan,
statusThisweek: BLE List View,
planNextWeek: Mqtt config
}
Here you can see my NodeJS code :
router.post ('/update', (req,res,next)=>{
userStatus = new wkStatus(req.body)
userStatus.save()
.then(status => {
res.redirect('/success');
console.log ("Status saved in DB")
})
.catch(err => console.log(err))
// return next;
});
//You can use ODM like mongoose and define a schema with mongoose.Schema. You can just
// see mongoose module document from npm. Use .save() for save an object in DB.
// Example :
// schema as admin
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const sha256 = require('sha256')
const adminSchema = new Schema({
fullName: { type: String, required: true },
userName: { type: String },
noc: { type: String, required: true },
mobileNumber: { type: String, required: true },
email: { type: String },
chacommAddress: {
contactPerson: { type: String },
country: { type: String },
address: { type: String },
city: { type: String },
pinCode: { type: String },
state: { type: String },
stateCode: { type: String },
},
address: {
country: { type: String },
city: { type: String },
pinCode: { type: String },
state: { type: String },
stateCode: { type: String },
address: { type: String },
CIN: { type: String },
GSTIN: { type: String }
},
password: { type: String, required: true },
userType: { type: Number, required: true },
createdAt: { type: Date, required: true },
uploadFile: { type: String, required: true },
bankdetails: {
bankName: { type: String },
accountNo: { type: String },
ifscCode: { type: String },
accountType: { type: String },
accountName: { type: String },
cancelledChequeCopy: { type: String }
},
isActive: { type: Boolean },
invoiceString:{type:String},
invoiceValue:{type:Number},
accountantName :{type:String} ,
accountantDesignation : {type:String},
referredBy:{type:String}
});
adminSchema.methods.comparePassword = function (password) {
let password_hash = sha256(password);
return bcrypt.compareSync(password_hash, this.password);
}
adminSchema.pre('save', function (next) {
if (!this.isModified('password'))
return next();
let password_hash = sha256(this.password);
bcrypt.hash(password_hash, null, null, (err, hash) => {
if (err)
return next(err);
this.password = hash;
next();
});
});
//export schema
// module.exports = mongoose.model('Admin', adminSchema)
// for save:
const admin = require('admin')
var obj= new admin({
// values as per model defined
})
obj.save()
const wkStatus = new wkStatus({
_id: new mongoose.Types.ObjectId(),
projectName: req.body.projectName,
clientName: req.body.clientName,
statusThisweek: req.statusThisweek,
statusLastWeek: req.statusLastWeek,
planNextWeek: req.planNextWeek
})
Status
.save()
.then(result => {
res.status(201).json({
message: "Data Created Successfully",
})
console.log(result) // show the response
})
.catch(err => {
res.status(500).json({error:err})
})
Try this way hope it will work. If need more you can message me
The schema what you are trying to create itself is wrong.
empName: {
projectName: { type: String },
clientName: { type: String },
statusLastWeek: { type: String },
statusThisweek: { type: String },
planNextWeek: { type: String }
}
The above schema can create objects like below: "empName" cannot be dynamic.
empName: {
projectName: BLE Mesh,
clientName: Tera,
statusLastWeek: BLE Scan,
statusThisweek: BLE List View,
planNextWeek: Mqtt config
}
If you want to store like what you have shown, where empName dynamically then you should make empName as Map
See https://mongoosejs.com/docs/schematypes.html#maps
I am trying to setup my patch api so that I can create a dynamic query to push, pull, and set data in my mongoose schema. I have plenty of values that I would change using set, but I also have an array of objects which would require me to call push when I need to insert and pull when I need to remove an item. I'm trying to find the best way to combine this into a dynamic structure.
Schema:
const StepSchema = new Schema({
position: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
due_date: {
type: Date
},
status: [{
label: {
type: String,
enum: ['Inactive', 'In Progress', 'Flagged', 'Complete'],
default: 'Inactive'
},
user: {
type: Schema.Types.ObjectId,
ref: 'users',
},
date: {
type: Date
}
}],
comments: [{
user: {
type: Schema.Types.ObjectId,
ref: 'users',
required: true
},
body: {
type: String,
required: true
},
date: {
type: Date,
required: true
},
}],
});
Api:
router.patch('/',
async (req, res) => {
let setQuery = req.body;
let pushQuery = {};
let pullQuery = {};
//remove id from set query
delete setQuery.id;
//if there is a comment
if(req.body.comment){
pushQuery.comments = req.body.comment
}
//if I need to remove a comment
if(req.body.remove_comment){
pullQuery.comments = {_id: req.body.remove_comment.id}
}
//Push new status into array
if(req.body.status) {
pushQuery.status = {
label: req.body.status,
user: req.user._id,
date: new Date()
};
delete setQuery.status;
}
//update step
await Step.findByIdAndUpdate(req.body.id, {$set: setQuery, $push: pushQuery, $pull: pushQuery})
.then(step => {
if(!step){
errors.noflow = "There was a problem updating the step";
return res.status(400).json(errors);
}
res.json(step)
})
.catch(err => {
console.log(err);
res.status(404).json(err);
});
});
I've been getting the following error when trying to push a new status into my document:
operationTime: Timestamp { bsontype: 'Timestamp', low: 1, high_:
1560978288 }, ok: 0, errmsg: 'Updating the path \'status\' would
create a conflict at \'status\'', code: 40, codeName:
'ConflictingUpdateOperators', '$clusterTime': { clusterTime:
Timestamp { bsontype: 'Timestamp', low: 1, high_: 1560978288 },
signature: { hash: [Object], keyId: [Object] } },
Oh, you're doing that $set and $push on a status. Your pushQuery is trying to have status be an array on the document, and your setQuery wants to set it to whatever it was on the actual body (I'm guessing the same object.
A quickfix would be to remove it from the set object:
delete setQuery.status
A reasonable and stable way to do this would be to actually only take the things from req.body which you really want for each of the stages. Example:
const { position, name, dueDate, status, comment, remove_comment } = req.body;
const setQuery = { position, name, dueDate };
const pushQuery = { status, comments: comment };
// ...
That way your queries are not conflicting in any way.
I have message document with groupId and createdTS fields.
and for query i have array of objects with groupId and lastVisit.
I want to query all messages per groupId after lastVisit
I tried with $in with groupIds but it is not filtering createdTS with lastVisit
member schema
const GroupMemberSchema = new mongoose.Schema({
userId: { type: String, required: true },
groupId: { type: String, required: true },
addTS: { type: Date, default: Date.now },
lastVisit: { type: Date, default: Date.now }
});
Message Schema
const GroupMessageSchema = new mongoose.Schema({
id: { type: String, required: true },
groupId: { type: String, required: true },
content: { type: String, required: true },
createdTS: { type: Date, default: Date.now },
});
for query
GroupMessage.find({groupId: {$in: groupIds}})
If I understood the question correct then you need to fetch records that match each groupId and at the same time are greater than appropriate lastVisit. If to translate it to MongoDB query it would be something like this:
{
"$or": [
{
"$and": [
{ "groupId": _groupId[i] },
{ "createdTS": { "$gt": _lastVisit[i] } }
]
},
...
]
}
Where _groupId[i] and _lastVisit[i] are array elements for list of groups and lastVisit timestamps.
my server side code
router.put('/api/user1', function(request, response){
Model.findById(request.body._id, function(err, user){
console.log(request.body);
if(err){
response.status(404).send(err);
}
else {
user.update(
{"_id": user._id },
{ '$push':
{ "feed": {"status":request.body.status, "comments":request.body.comments} }})
}
})
});
my client side code
vm.statusUpdateUser = function(user,status,comments){
console.log(status);
var payload = {_id: user._id, status: status, comments:comments }
if(user){
$http.put('/api/user1', payload).then(function(response){
console.log('status details send'+ user.feed.status);
vm.getUsers();
})
}
}
here is my mongoose model
var UsersSchema = new Schema({
name: {
type: String,
required: true
},
diameter: {
type: String,
required: true,
},
atno: {
type: Date,
default : Date.now
},
holder: {
type: Date,
},
toolType: {
type: String,
required: true
},
feed:[{
status: {
type: String
},
comments: {
type: String
},
posted_date: {
type: Date,
default : Date.now
}
}]
});
I am trying to push status and comments into my feed array
but it not going through, please help with this issue.
the get put delete post all working fine but adding a key value pair into an array is not working for me
any idea guys??