How to mongoose aggregate find data from a filed of array? - mongodb

I have an array like this on DB.
[{
_id: 61c9b7ac365cae3e9e406d8d,
user: 61c879d080d04078d7342b34,
cart:
[
_id:"61c85d2c7ab0861b703da7d3"
title:"some title"
price:100
description:"some des",
user: {_id:"61c7f81469176d17a540712e" }
]
}]
I used:
const { sellerId } = req.params;
const order = await Orders.find({ "user": { "$in": sellerId } })
.sort("-created") // or .sort({ field: 'asc', created: -1 });
I want all the data of cart items user field _id..

I have an array like this on DB.
Do you mean u have a mongoDB collection named Orders with the above data?
I want all the data of cart items user field _id..
Find will return the cursor to the matching records. Try
await Orders.find({ "user": { "$in": sellerId } })
.sort("-created").forEach(function(err, order) {
console.log(order.cart)
});

Related

update Object inside array of Object with mongoose

I'm trying to update and object inside array in MongoDB.
my model is:
let userSchema = new mongoose.Schema({
userName: {
type: String
},
password: {
type: String
},
history: []
});
And inside history each element is from the next type:
id, array(named ing_array) and boolean field called favorite.
I'm trying to update the favorite field with mongoose with the userName and the id.
I tried to do this query and I didn't succed.
Could some one tell me whats worng?
[object photo]: https://i.stack.imgur.com/2mYpP.png
User.findOneAndUpdate(
{ "userName": user_name, "history.id": id },
{ "$set": { "history.$.favorite": true }}
);
You have to use arrayFilters in this way:
db.collection.update({
"userName": "uname",
"history.id": 1
},
{
"$set": {
"history.$[element].favorite": false
}
},
{
"arrayFilters": [
{
"element.id": 1
}
]
})
Note that update query has the format: update(query, update, options) (Check the docs).
When you do { "userName": user_name, "history.id": id } you are telling mongo "Give me all documents where userName is user_name and array history has an id with value id. This return all history array because it belows to the document.
To update an specific object into the array is neccessary to use arrayFilters to tell mongo which object do you want to update. In this case the object where id is equal to 1. You can use as you want to match wit your requirements.
Example here

MongoDB - Add / update to list of objects on document

I have a user collection, and each user has a list of products. I need to update a product using it's ID or add the product if it doesn't exist.
How can I update the product by it's id?
User Collection:
{
"_id": {
"$oid": "5fc06554266266edf5643231"
},
"products": [
{
"id": 123,
"name": "test product"
}
]
}
Using the following code I'm able to add the product, but can't update the product by it's ID.
db.users.updateOne({_id: ObjectId('5fc06554266266edf5643231')}, {
'$addToSet': {
'products': {
'id': 123,
'name': 'foobar'
}
}
}, {upsert:true})
Well, i will recommend to you to re-think your schema.
Maybe you need to create a collection called Products and in the user collection put all the id's of the products on a field called product. Then you can create a query with a populate function. Something like this
const user = await User.find(query, options)
.then(async (result) => result)
.catch((err) => logger.info(err));
const populateProducts = await Products.populate(user, populateProductsOptions)
.then(async (data) => data)
.catch((err) => logger.info(err));
But if you don't want to modify your schema you have to do several querys. There is no way to do this in single query. You have to search the document first:
If document exist:
db.users.updateOne( {_id: 123456 , yourQueryProduct ,
false ,
true);
db.users.updateOne( {_id: 123456: 123456 } ,
{$pull: {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
db.users.updateOne( {_id: 123456: 123456 } ,
{$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
else if document don't exist you can addToSet directly
The issue is that on this line: db.users.updateOne({_id: "5fc06554266266edf5643231"}
The _id field is being interpreted as a String, but the document you want to update saves its _id as an ObjectId. All you have to do it make it an ObjectId is this:
db.users.updateOne({_id: ObjectId("5fc06554266266edf5643231")}, {
'$addToSet': {
'products': {
'id': 123,
'name': 'foobar'
}
}
}, {upsert:true})

mongodb find and update one with multiple conditions

{
roomId: "id",
questions:{
q1:{
user1:"user1's work"
}
}
}
I'm trying to query mongodb with multiple conditions, that roomId has to match, and questions must be q1, and in q1 there must be a user1.
Here's what I've tried so far. Using and operator, but doesn't seems to work.For now I'm using find, as I read in the docs that updateMany has the same query selector as find.
const result = await collection.find({
$and: [
{
roomId: roomId,
},
{
questions: {
currentQuestion: {
userName,
},
},
},
],
});
My schema:
{
roomId: "id",
roomName:"roomName",
questions:{
question1:{
user1:"user1's work",
userN: "userN's work"
},
questionN:{
user1:"",
userN:""
}
}
}
My expected input , (roomId, currentQuestion, userName) for query conditions,"userWork" to be inserted to what's under userName (user1 - userN).
Expected output, that the user's work gets updated with "userWork", under the right room, right currentQuestion and the right user.
You need this query I think:
db.collection.find({
"roomId": "id",
"questions.q1.user1": {
$exists: true
}
})
This query find a roomId which match your 'id' and then, check if exists the element questions.q1.user1.
Mongo playground example here
PS: You said update but... what do you want to update?
Assuming your schema is like
{
roomId: "id",
questions: {
q1: {
user1: "user1's work",
currentQuestion: "currentQuestion1"
}
}
}
Then, the query to update the currentQuestion field whose match the id and has existing questions.q1.user1 is this:
db.collection.update({
"roomId": "id",
"questions.q1.user1": {
$exists: true
}
},
{
"$set": {
"questions.q1.currentQuestion": "new question"
}
})
Example here
Note that if currentQuestion is one level up, you only have to modify $set object.
If you are not asking for this, please provide a complete schema, example input and expected output.

How can I query the value of an object rather than the key value pair in MongoDB

I've store an array on my user object which holds all of the data
{
_id: ObjectId(#############)
fname: 'Bob',
lname: 'Vargas',
data: [
// the data I want
]
}
I am using express to get his data like this:
db.users.findOne( { _id: ObjectId(#############) }, { data: 1, _id: 0 } );
but that is giving me an object rather than the array:
{ data: [ /* my data */ ]}
how can I get just the array?
UPDATE
app.get('/user/:id/data', function (req, res, next) {
db.users.findOne(
{ _id: mongojs.ObjectId(req.params.id) },
{ data: 1, _id: 0 },
function (err, userData) {
if (err) {
res.send(err);
}
res.json(userData);
}
);
});
Add projection to query result:
db.users.findOne( { _id: ObjectId(#############) }, {_id:0, data:1} )
Use 0 to exlude field from result (_id is included by default), and 1 to include field in result.
MongoDB returns object per document. But you can manually map objects on client side:
db.users.findOne( { _id: ObjectId(#############) }, {_id:0, data:1} )
.map(function(d){ return d.data; }))
MongoDB's findOne() will only return an object, not an array; thus the One. Instead you will need to receive it as and object and then get the value.
If you are doing this from mongo shell then there is no way around unless you want to move the data into its own collection. Otherwise you can get the array from the object in your application.
UPDATE:
in your express response, only encode the data value, like this
res.json(userData.data);

Resolving a ref inside of a MongoDB aggregate

I have a Product model object that has the following field in its schema:
category : { type: ObjectId, turnOn: false, ref: "category" }
It references a category model that has a title field in it:
var categorySchema = Schema({
title : { type: String }
});
I'm using the product.category property (which is of type ObjectId as shown above) in a MongoDB aggregate but really want the category.title property from the category model rather than _id in the final resultset.
The following code gets the job done, but you'll see that I'm having to do some looping at the end to "resolve" the title field for the given product.category (ObjectId). Is there anyway to do all of that within the aggregate? In other words, is there a way to get the category model object's title field in the groups that are returned rather than having to do the extra looping work? Based on posts I've researched I don't see a built-in way but wanted to double-check.
getProductsGroupedByCategory = function(callback) {
Category.find(function(err, cats) {
var aggregate = [
{
$group: {
_id: "$category",
products: {
$push: {
title: "$title",
authors: "$authors",
publishDate: "$publishDate",
description: "$description"
}
}
}
},
{
$sort: {
"_id": 1
}
}
];
Product.aggregate(aggregate, function(err, catProducts) {
//Grab name of category and associate with each group
//since we only have the category_id at this point
for (var i = 0; i<catProducts.length;i++) {
var catProduct = catProducts[i];
for (var j=0;j<cats.length;j++) {
if (catProduct._id.toString() === cats[j]._id.toString()) {
catProduct.category = cats[j].title;
}
}
};
callback(err, catProducts);
});
});
}, //more code follows
An example datum would be helpful along with what you need out of it. From What I understand you are looking to get the title in to the grouping criteria and that should be doing by having a compound grouping criteria i.e.
_id: {category: "$category", title: "$title"}
If the title is within an array, you should do unwind, group and then wind again to achieve the result.