I am trying to get a single array value from mongodb, but when i try i get the whole object - node.js

1.I Don't get the Item in Electro Array but the whole doc
getItem(data){
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id,
'swap.Items.Electro.id':data.id }, function(err,item){
if(err){
return (err);
}
if(item){
console.log(item);
}
});
} // EOF
This is my Schema
1.I am trying to get the item i create in Electro only, I don't want the whole object i am getting at the moment.
var swapSchema = new mongoose.Schema({
swap: {
name: String,
Items: {
Electro: [
{
name: String,
info: String,
price: Number,
dateCreated: Date,
category: String,
id: Number
}
]
}
}
});

Use the projection field :
If you want to get all the array :
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id},
{ 'swap.Items.Electro' : 1}
, function(err, obj){
will return something like :
{
_id: ObjectId("sdfsdfsdf"),
Electro:[{....},{....}]
}
Or if you want only the object in the array who match the query :
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id},
{ 'swap.Items.Electro.$' : 1}
, function(err, obj){
will return something like :
{
_id: ObjectId("sdfsdfsdf"),
Electro:{your match object}
}

Related

MongoError: The positional operator did not find the match needed from the query. at Function.create()

I am trying to update values into an object array(users) if it does not already exist in MongoDB. Here is my Schema:
ownerid:{
type: Number,
required: 'This field is required'
},
name:{
type: String
},
capacity:{
type: Number
},
basePrice:{
type: Number
},
users:[{
id: Number,
price: Number,
target: Number,
frequency: Number
}],
filePath:{
type: String
},
status:{
type: String
}
});
The following is my router method:
app.post('/userBid',urlEncodedParser,function(req,res){
resName=req.body.resName;
console.log(resName);
Resource.find({"name":resName},{"users.id": userid},function(err,existingUser){
if (!existingUser){
console.log("already in queue");
//res.render('userHome.ejs');
}
else{
console.log("in update");
Resource.update({'name': resName},
{'$set': {
'users.$.frequency': 1,
'users.$.id': userid,
'users.$.price': req.body.price,
'users.$.target': req.body.target
}},{'multi': true},
function(err,model) {
if(err){
console.log(err);
return res.send(err);
}
return res.json(model);
});
}
});
});
I have tried using $push but that does not seem to work either. Also I can't use '0' instead of '$' as multiple users will be inserted by the users and I need to store them all.
Issue :
Reason why we use $ is to update a specific object/few specific objects in an array field that meet our condition. So when you use any positional operators like $ or $[] then in filter part of .update({filterPart},{updatePart}) query you need to use a filter to find specific object in array. So for example if id field is unique in users array then you can use it to filter/find the object needs to be updated.
Try this below code :
app.post("/userBid", urlEncodedParser, function (req, res) {
resName = req.body.resName;
console.log(resName);
/** Use findOne if `name` is unique.
* Cause `existingUser` will be array, instead findOne will return an object or null - So you can just do if(existingUser)to check true values */
Resource.find({ name: resName }, { "users.id": userid }, function (
err,
existingUser
) {
if (!existingUser) {
console.log("already in queue");
//res.render('userHome.ejs');
} else {
console.log("in update");
Resource.update(
{ name: resName, "users.id": userid }, /** `"users.id": userid` is the only change needed */
{
$set: {
"users.$.frequency": 1,
"users.$.id": userid,
"users.$.price": req.body.price,
"users.$.target": req.body.target,
},
},
{ multi: true },
function (err, model) {
if (err) {
console.log(err);
return res.send(err);
}
return res.json(model);
}
);
}
});
});

updating values in nested object arrays Mongoose Schema

I have my schema designed like this
const templateSchema = new Schema({
Main: {
text: String,
textKey: String,
index: String,
part: String,
overallStatus: String,
subjects: [
{
id: String,
text: String,
textKey: String,
index: String,
type: String,
comment: String,
image: String,
answer: String,
}
and I have to update subjects text and subject id and I am doing it like this
router.post("/edit", (req, res, next) => {
Template.findOneAndUpdate({
id: req.body.id,
text: req.body.text
}).then(updatedTemp => {
console.log(updatedTemp);
if (updatedTemp) {
res.status(200).json({
message: "Template updated.."
});
} else {
res.status(404).json({
message: "Checklist not found"
});
}
});
});
it returns template updated and status 200 but it doesn't update the new values. How can i access subject ID and subject text in this schema
so, According to the provided schema,
you should find inside the array, and update there,
you could do something like this:
router.post("/edit", (req, res, next) => {
Template.update(
{
"Main.subjects.id": req.body.oldId,
"Main.subjects.text": req.body.oldText,
//you can pass some more conditions here
},
{
$set: {
"Main.subjects.$.id": req.body.id,
"Main.subjects.$.text": req.body.text
}
}
)
.then(updated => {
if (updated.nModified) {
res.status(200).json({
message: "Template updated.."
});
} else {
//not updated i guess
}
})
.catch(error => {
//on error
});
});
so payload in body you need to pass :
oldId : <which is currently there>,
oldText: <which is currently there>,
id: <by which we will replace the id field>
text:<by which we will replace the txt>
NOTE:
assuming , id or text will be unique among all the docs.
sample data:
{
"_id" : ObjectId("5be1728339b7984c8cd0e511"),
"phases" : [
{
"phase" : "insp-of-install",
"text" : "Inspection of installations",
"textKey" : "",
"index" : "1.0",
"subjects" : [...]
},...]
}
we can update text here like this [in the top most level]:
Template.update({
"_id":"5be1728339b7984c8cd0e511",
"phases.phase":"insp-of-install",
"phases.text":"Inspection of installations"
},{
"$set":{
"phases.$.text":"Some new text you want to set"
}
}).exec(...)
but, incase you want to do deep level nested update,
you can have a look at this answer : here by #nem035

Add or push new object to nested mongodb document

I can't seem to find an answer to this on Stack or in the Mongoose docs. How do I added a new object into a nested document?
This is my current schema:
var SessionsSchema = mongoose.Schema({
session: {
sid: String,
dataloop: {
timeStamp: Date,
sensorValues:{
value: Number,
index: Number
}
}
}
});
Upon receiving new data from the client, I need to push into the existing session document, i've tried both $addToSet and $push but neither are giving me the correct results.
This is the $push:
Sessions.findOneAndUpdate(
{ 'session.sid': sessionID },
{
'$push:': {dataloop:{
timeStamp: datemilli,
sensorValues:{
value: pressure,
index: indexNum,
sessionTime: relativeTime
}
}
}
},
function(err,loop) {
console.log(loop);
}
)
Here is my expected output:
_id:58bb37a7e2950617355fab0d
session:Object
sid:8
dataloop:Object
timeStamp:2017-03-04 16:54:27.057
sensorValues:Object
value:134
index:18
sessionTime:0
dataloop:Object // <----------NEW OBJECT ADDED HERE
timeStamp:2017-03-04 16:54:27.059
sensorValues:Object
value:134
index:18
sessionTime:0
dataloop:Object // <----------ANOTHER NEW OBJECT
timeStamp:2017-03-04 16:54:27.059
sensorValues:Object
value:134
index:18
sessionTime:0
__v:0
If you consider to change your Schema to include a dataloop array :
var SessionsSchema = mongoose.Schema({
session: {
sid: String,
dataloop: [{
timeStamp: Date,
sensorValues: {
value: Number,
index: Number
}
}]
}
});
You could use $push on session.dataloop to add a new dataloop item :
Sessions.findOneAndUpdate({ 'session.sid': sessionID }, {
'$push': {
'session.dataloop': {
timeStamp: datemilli,
sensorValues: {
value: pressure,
index: indexNum,
sessionTime: relativeTime
}
}
}
},
function(err, loop) {
console.log(loop);
}
)

Mongoose avg function by request field

I want to return the average of a Number field by another field(the document ID field):
Comments.aggregate([
{$group:
{
_id: ($nid: req.adID), // here is the field I want to set to req.adID
adAvg:{$avg:"$stars"}
}
}
], function(err, resulat){
if(err) {
res.send(String(err));
}
res.send(resulat);
}
)
The ID field is in the request object, req.adID, I didnt find an example for grouping by a query (_id : 'req.adID').
My schema looks like:
var CommentSchema = new Schema(
{
_id: Schema.Types.ObjectId, //scheme
nid:Number, // ad ID
posted: Date, // Date
uid: Number, // user ID
title: String, //String
text: String, // String
stars: Number //String
}
);
Also if someone can write the return data for this query it will be great!
From your follow-up comments on the question, looks like your aggregation needs the $match pipeline to query the documents that match the req.adID on the nid field, your $group pipeline's _id field should have the $nid field expression so that it becomes your distinct group by key. The following pipeline should yield the needed result:
var pipeline = [
{ "$match": { "nid": req.adID } },
{
"$group": {
"_id": "$nid",
"adAvg": { "$avg": "$stars" }
}
}
]
Comments.aggregate(pipeline, function(err, result){
if(err) {
res.send(String(err));
}
res.send(result);
})

Get all documents of a type in mongoose but only with 1 specific item of each documents array

I'm using Express 4 and Mongoose for my REST API. So I have multiple documents of the type "shop". Each shop holds (besides other information) an array called "inventory" that holds again multiple items. Each item itself has properties like name and price.
Now I would like to have an API call where I can get all the shops but only with their "cheapest" product item in the json response. But I'm totally stuck in creating this query that returns all my shops but instead of including all items of the inventoryjust includes the inventory item with the lowest price as the only item in the inventory array.
I found some hints on how to exclude fields using something like the following query but there the whole array will be excluded:
Shop.find({}, {inventory: 0},function(err, shops) {
if (err) {
res.send(err);
} else {
res.json(shops);
}
});
Update 1: My Schemas
// Shop
var ShopSchema = new Schema({
name: { type: String, required: true},
address: {
street: String,
zipCode: Number,
city: String
},
inventory: [InventoryItemSchema]
});
// InventoryItem
var InventoryItemSchema = new Schema({
name: { type: String, required: true},
currentPrice: {
amount: { type: Number, required: true },
added: Date
},
pastPrices: []
});
Update 2: This is what I came up
Shop.find(function(err, shops) {
if (err) {
res.send(err);
} else {
shops.forEach(function(shop) {
// Only keep the currently cheapest inventory Item in the array
var cheapestInventoryItem;
shop.inventory.reduce(function (previousItem, currentItem) {
if (currentItem.currentPrice.amount < previousItem.currentPrice.amount) {
cheapestInventoryItem = currentItem;
return currentItem;
} else {
cheapestInventoryItem = previousItem;
return previousItem;
}
});
shop.inventory = [cheapestInventoryItem];
});
res.json(shops);
}
});
Mongodb find method returns a document. So in your case it would be array of shops with their fold fields anyway.
You can filter items with js:
var cheapestItem;
var cheapestPrice = shop.inventory.items.reduce(function (lowest, item) {
if (item.price < lowest) {
cheapestItem = item;
return item.price;
}
}, Infinity);
Or you can normalize your schema and create collection Items:
[{itemId: 1, shopId: 1, price: 100}]
So the query is:
db.Item.group(
{
key: { shopId: 1, itemId: 1, price: 1 },
reduce: function ( lowest, res ) { if (result.price < lowest) return result.price },
initial: Infinity
})
So you must get shopId and itemId with lowest price

Resources