Cannot query nested document's _id (other fields work) - mongodb

I want to find all documents where vendor._id has a certain value. Below is the code, I tried, but it returns nothing.
let name = sampleData.name, _id = sampleData._id
Product.find({"vendor._id":ObjectID(_id)}).then((products) => {
//returns empty array
})
With the same method I tried to query a different field and it works. But I want to query with _id because other fields could vary with time.
Product.find({"vendor.name":name}).then((products) => {
//returns all documents that satisfy the condition.
})
Below is a sample document which I want to find
{
"status" : "active",
"connectedFarms" : [
{
"_id" : "5c412c62bf8a6602f04ae0bf",
"status" : "inActive",
"margin" : 10,
"price" : 55
},
{
"_id" : "5c4567bcb3845b0536a4d92e",
"status" : "inActive",
"margin" : 20,
"price" : 60
},
{
"_id" : "5c4567c4b3845b0536a4d931",
"status" : "active",
"margin" : 7,
"price" : 53.5
}
],
"vendor" : {
"_id" : ObjectId("5c3fcc0c7657ee02ac24bc21"),
"name" : "manna"
}
}
And here is the schema for this document.
let ProductSchema = new mongoose.Schema({
vendor:{_id:String, name:String},
connectedFarms:[{_id:String, name:String, status:String, price:Number, margin:Number}],
status:{
type:String,
trim: true,
minlength:1
}
});

Let's take a different approach on this, and make vendor its own schema. Mongoose does not allow you to nest schemas, so you cannot make the vendor._id a true ObjectID.
Vendor Schema
const VendorSchema = new mongoose.Schema({
name: string
});
module.exports = mongoose.model('Vendor', VendorSchema);
Product Schema
const ProductSchema = new mongoose.Schema({
vendor: {
type: mongoose.Types.ObjectID,
ref: 'Vendor'
},
connectedFarms: [{
_id: String,
name: String,
status: String,
price: Number,
margin: Number
}],
status: {
type: String,
trim: true,
minlength: 1
}
});
module.exports = mongoose.model('Product', ProductSchema);
Now when you want to query a product based on the vendors _id, it's very simple! All you need to do is supply the _id of the vendor in the query. NOTE: There is no reason to convert the _id to an ObjectID in the query, as mongoose accepts strings and converts them later on.
Query
const vendorID = myVendor._id;
Product.find({ vendor: vendorID })
.then((products) => {
// Do something with the found products
});
That's it! Much simpler to do, and much cleaner in the database. The vendor field is now easier to reference. You also have the ability to get the full vendor object in a query if desired by populating in the query. The difference is, the population will return the vendor name and _id, rather than just the _id. To do this, run the following:
Product.find({ vendor: vendorID })
.populate('vendor')
.then((products) => {
// Do something with the populated found products
});

Related

mongoose find collection by _id in a list of array

Here's my Schema
var PositiveSchema = new mongoose.Schema({
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
name: String,
restrictAwardTo: Object
})
Now restrictAwardTo saves the data in this format
"restrictAwardTo" : [
{
"_id" : "5c31907d908eb8404657cbf0",
"firstName" : "Admin 2a"
},
{
"_id" : "5c1a7677c98da061141475a8",
"firstName" : "Justice"
},
{
"_id" : "5c1a7677c98da061141475a9",
"firstName" : "Itik"
}
],
How can I search inside my document using one of the _id listed under restrictAwardTo? I tried the solutions given below
mongooseJS find docs with IDs in an array
mongoose query: find an object by id in an array but it returns empty.
in Robo3t db.getCollection('positives').find({ 'restrictAwardTo._id' : ObjectId('5c31907d908eb8404657cbf0') })
Update: In Robo3t, this query db.getCollection('positives').find({ 'restrictAwardTo._id' : {$in: ['5c1a7677c98da061141475a7']} }) works. Now I'm making it work for mongoose too.
Here's the mongoose that works for me:
Positive.find({ schoolID: mongoose.mongo.ObjectId(schoolID), "restrictAwardTo._id": { $in: [userID]} })
But I'm not entirely sure of the performance for large records.
You could go through this way.
Positive.findOne({'restrictAwardTo': {$elemMatch: {_id: userID}}},
(err,schoolInfo) => { });

Referencing for mongoose

i'm currently trying to reference a collection called items with the structure below
packageSchema = schema({
recipient: String,
contents: [{item :{type: mongoose.Schema.Types.ObjectId,
ref: 'items', required : true}, amount: String}]
Below is my code for getting one package via its id
getOnePackage : function(id,callback)
{
packageModel.findById(id,callback)
.populate('contents')
}
So when i call the above function i'm expecting to get this result
{
recipient : Dave
contents : [
{item : {
_id:5d2b0c444a3cc6438a7b98ae,
itemname : "Statue",
description : "A statue of Avery"
} ,amount : "2"},
{item : {
_id:5d25ad29e601ef2764100b94,
itemname : "Sugar Pack",
description : "Premium Grade Sugar From China"
} ,amount : "5"},
]
}
But what i got from testing in Postman is this :
{
recipient : Dave,
contents : []
}
May i know where did it went wrong? And also how do i prevent mongoose from automatically insert an objectId for every single element in the contents array....
Because element in contents array is object with item field so your populate should be:
.populate('contents.item')

Full Text Search on mLab with mongoose: MongoError: text index required for $text query

I'm trying to perform a full text search on a database on mLab. However, apparently the text indexes are not being created.
Mongoose version is 5.4.16
Schema:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var mySchema = new Schema({
title: {
type: String,
trim: true,
required: true
},
description: {
type: String,
trim: true
}
});
mySchema.index({
title: "text",
description: "text",
});
mongoose.model("Model", mySchema);
module.exports = mongoose.model("Model");
Use following to perform the search:
Model.find({
$text: { $search: query }
}).exec(function(err, codes) {...}```
I get the following error:
MongoError: text index required for $text query
I don't know why but I had the same problem with Mongoose and Mlab.
Manually I did the following to solve it.
1) Connect to mlab using the mongo shell
mongo ds245387.mlab.com:45387/<dbname> -u <dbuser> -p <dbpassword>
2) Run db.products.createIndex( { title: "text", "description": "text" } )
3) db.products.getIndexes() should return something like:
{
"v" : 2,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"name" : "title_text_description_text",
"ns" : "database-name.products",
"weights" : {
"description" : 1,
"title" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 3
}
Note: products is your collection name
4) Try your query again!
MongoDB text-search reference

Mongo - Count of empty double nested arrays

Say I have this structure
{
"_id" : "4klhrj5hZ",
"name" : "asdf",
"startTime" : ISODate("2016-09-20T22:22:08.082Z"),
"columns" : [
{
"_id" : ObjectId("57e1b69087ceb4392ebdf7f4"),
"createdAt" : ISODate("2016-09-20T22:22:08.088Z"),
"rows" : [
{
"value" : "adf",
"_id" : ObjectId("57e1b7867598bd39a72876ef")
}
]
},
{
"_id" : ObjectId("57e1b69087ceb4392ebdf7f3"),
"createdAt" : ISODate("2016-09-20T22:22:08.088Z"),
"rows" : [
{
"value" : "we",
"_id" : ObjectId("57e1b69287ceb4392ebdf7f5"),
]
},
{
"_id" : ObjectId("57e1b69087ceb4392ebdf7f2"),
"createdAt" : ISODate("2016-09-20T22:22:08.086Z"),
"rows" : [
{
"value" : "asdf",
"_id" : ObjectId("57e1b7be7598bd39a72876f0")
}
]
}
]
}
Where I first have an array of columns, then an array of rows with each columns. An array of arrays... I'm trying to write a count query to tell me how many top level documents contain ALL empty array of arrays. So in this example, columns[0-2].rows.length === 0, not columns could be any length. The thing that is tripping me up the most from examples i've seen, is the doing the nested array dynamically and not referring to it like
columns.0.rows
Thanks!
EDIT: Clarification
Here is the mongoose schema to help clarify
var RowSchema = new Schema({
value: String,
createdAt:{
type: Date,
'default': Date.now
}
});
var ColumnSchema = new Schema({
rows: [RowSchema],
createdAt:{
type: Date,
'default': Date.now
}
});
var ItemSchema = new Schema({
_id: {
type: String,
unique: true,
'default': shortid.generate
},
name: String,
columns: [ColumnSchema],
createdAt:{
type: Date,
'default': Date.now
}
})
I want to run a query to find all Item's that contain zero rows in all columns. So I know how to find an array that is empty:
Item.find({ columns: { $exists: true, $eq: [] } })
But I want something like
Item.find({ 'columns.rows': { $exists: true, $eq: [] } })
Sorry for the unclear explanation, just get so wrapped up in it sometimes you forget to set the proper context. Thanks.

How to update a subdocument in mongodb

I know the question have been asked many times, but I can't figure out how to update a subdocument in mongo.
Here's my Schema:
// Schemas
var ContactSchema = new mongoose.Schema({
first: String,
last: String,
mobile: String,
home: String,
office: String,
email: String,
company: String,
description: String,
keywords: []
});
var UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
contacts: [ContactSchema]
});
My collection looks like this:
db.users.find({}).pretty()
{
"_id" : ObjectId("5500b5b8908520754a8c2420"),
"email" : "test#random.org",
"password" : "$2a$08$iqSTgtW27TLeBSUkqIV1SeyMyXlnbj/qavRWhIKn3O2qfHOybN9uu",
"__v" : 8,
"contacts" : [
{
"first" : "Jessica",
"last" : "Vento",
"_id" : ObjectId("550199b1fe544adf50bc291d"),
"keywords" : [ ]
},
{
"first" : "Tintin",
"last" : "Milou",
"_id" : ObjectId("550199c6fe544adf50bc291e"),
"keywords" : [ ]
}
]
}
Say I want to update subdocument of id 550199c6fe544adf50bc291e by doing:
db.users.update({_id: ObjectId("5500b5b8908520754a8c2420"), "contacts._id": ObjectId("550199c6fe544adf50bc291e")}, myNewDocument)
with myNewDocument like:
{ "_id" : ObjectId("550199b1fe544adf50bc291d"), "first" : "test" }
It returns an error:
db.users.update({_id: ObjectId("5500b5b8908520754a8c2420"), "contacts._id": ObjectId("550199c6fe544adf50bc291e")}, myNewdocument)
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 16837,
"errmsg" : "The _id field cannot be changed from {_id: ObjectId('5500b5b8908520754a8c2420')} to {_id: ObjectId('550199b1fe544adf50bc291d')}."
}
})
I understand that mongo tries to replace the parent document and not the subdocument, but in the end, I don't know how to update my subdocument.
You need to use the $ operator to update a subdocument in an array
Using contacts.$ will point mongoDB to update the relevant subdocument.
db.users.update({_id: ObjectId("5500b5b8908520754a8c2420"),
"contacts._id": ObjectId("550199c6fe544adf50bc291e")},
{"$set":{"contacts.$":myNewDocument}})
I am not sure why you are changing the _id of the subdocument. That is not advisable.
If you want to change a particular field of the subdocument use the contacts.$.<field_name> to update the particular field of the subdocument.