querying nested object arrays from mongodb / nodejs - node.js

I am trying to figure out how to query the nested objects inside the Components object. The data was inserted from a parsed json file.
Query
var query = {}
cursor = db.collection("workflows").find(query).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
});
This data is returned when I run the query above:
At this point i'm just trying to get it to filter in some manner. I've tried Name:'Test WF' and other variations of that but still can't get a filtered response.
[ { _id: 5c77040838f9d322b89bbd82,
texto:
{ _id: 12,
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c7704164413692978a9dd1a,
texto:
{ _id: 'Workflow-2019.02.22-23.21.15-MKRU',
LocalCachePath: 'Z:\\MAITest\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c77046335b012379c99951b,
texto:
{ _id: '154',
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c7704787bde6f36543d1016,
texto:
{ _id: 'Workflow-2019.02.22-23.21.15-MKRU',
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } } ]
Any insight would be helpful i'm stumbling through this one step at a time.
Here's another query that is giving me results but i guess my issue is going to be to parse out my results as variables.
var query = {'texto.Components.0.Name' : {$gt: ''}}
// var query = {'testo.Name' : {$gt: ''} }
cursor = db.collection("workflows").find(query).toArray(function(err, result) {
if (err) throw err;

Use dot notation (e.g. texto.Name) to query and retrieve fields from nested objects, example:
var query = {'texto.Name': 'Test WF'}

Simply
db.getCollection('TestQueries').find({'texto.Name': 'Test WF'})
Regex used for Case Insensitive.
db.getCollection('TestQueries').find({"texto.Name":{
'$regex' : '^test wa$', '$options' : 'i'
}})
Using collation
db.fruit.createIndex( {"texto.Name": 1},{ collation: {
locale: 'en', strength: 2
} } )
db.getCollection('TestQueries').find(
{ "texto.Name": "test wa" } ).collation( { locale: 'en', strength: 2 }
)

You can also use $elemMatch. It is longer, but allows for multiple fields query.
db.getCollection('TestQueries').find({texto: {$elemMatch: {Name: "test wa"} }))
Official docs here

Related

How can I find specific document and update a value of specific key inside array?

I have a structure like this:
{
_id: new ObjectId("634aa49f98e3a05346dd2327"),
filmName: 'Film number 1',
episodes: [
{
episodeName: 'Testing 1',
slugEpisode: 'testing-1',
_id: new ObjectId("6351395c17f08335f1dabfc9")
},
{
episodeName: 'Testing 2',
slugEpisode: 'testing-2',
_id: new ObjectId("6351399d9a2533b9be1cbab0")
},
],
},
{
_id: new ObjectId("634aa4cc98e3a05346dd232a"),
filmName: 'Film number 2',
episodes: [
{
episodeName: 'Something 1',
slugEpisode: 'something-1',
_id: new ObjectId("6367cce66d6b85442f850b3a")
},
{
episodeName: 'Something 2',
slugEpisode: 'something-2',
_id: new ObjectId("6367cd0e6d6b85442f850b3e")
},
],
}
I received 3 fields:
_id: Film _id
episodeId: Episode _id
episodeName: The content I wish to update
I tried to find a specific Film ID to get a specific film, and from then on, I pass an Episode ID to find the exact episode in the episodes array. Then, update the episodeName of that specific episode.
Here's my code in NodeJS:
editEpisode: async (req, res) => {
const { _id } = req.params
const { episodeId, episodeName } = req.body
try {
const specificResult = await Films.findOneAndUpdate(
{ _id, 'episodes._id': episodeId },
{ episodeName }
)
console.log(specificResult)
res.json({ msg: "Success update episode name" })
} catch (err) {
return res.status(500).json({ msg: err.message })
}
},
But what console.log display to me is a whole document, and when I check in MongoDB, there was no update at all, does my way of using findOneAndUpdate incorrect?
I'm reading this document: MongooseJS - Find One and Update, they said this one gives me the option to filter and update.
The MongoDB server needs to know which array element to update. If there is just one array element to update, here's one way you could do it. (I picked a specific element. You would use your req.params and req.body.)
db.films.update({
"_id": ObjectId("634aa4cc98e3a05346dd232a"),
"episodes._id": ObjectId("6367cd0e6d6b85442f850b3e")
},
{
"$set": {
"episodes.$.episodeName": "Something Two"
}
})
Try it on mongoplayground.net.
You can use the filtered positional operator $[<identifier>] which essentially finds the element or object (in your case) with a filter condition and updates that.
Query:
const { _id } = req.params
const { episodeId, episodeName } = req.body
await Films.update({
"_id": _id
},
{
$set: {
"episodes.$[elem].episodeName": episodeName
}
},
{
arrayFilters: [
{
"elem._id": episodeId
}
]
})
Check it out here for example purpose I've put ids as numbers and episode name to update as "UpdatedValue"

searching with elasticsearch js with multiple fields

Hi guys I have this code :
let test = await client.search({
index: 'test',
type: 'doc',
body: {
query: {
match: {
title: 'something',
}
}
}
});
this code is searching by 1 query which is title: 'something' , but I want to change it to search with multiple keys, for example:
let test = await client.search({
index: 'test',
type: 'doc',
body: {
query: {
match: {
title: 'something',
desc: 'some Qualifications'
}
}
}
});
but this code doesn't work and I can't find anything that will work like that, can anyone help?
You need to combine all the match queries using a bool/must query, like this:
let test = await client.search({
index: 'test',
type: 'doc',
body: {
query: {
bool: {
must: [
{
match: {
title: 'something',
}
},
{
match: {
desc: 'some Qualifications',
}
}
]
}
}
}
});

Why mongoose populate return me an illegal array and how to do with it?

I use mongoose populate a list of data like:
Account.findOne({_id:accountId}).populate({
path:"orders.order",
match:{_id:orderId},
selecte:'',
options:{
limit:1
}
}).exec(function (err, doc) {
if (err) {
callback(err);
}
callback(doc);
})
}
and what I get:
[ { order: null },
{ order: null },
{ order: null },
{ order: null },
{ order: null },
{ order: null },
{ order:
{ date: Tue May 31 2016 12:56:36 GMT+0800 (HKT),
dishs: [Object],
__v: 0,
message: 'plz deliver after 5 p.m',
price: 5,
address: [Object],
shop: null,
user: 574bfebc29cf722c17f8eafe,
_id: 574d198451615ce01a5e1a81 } } ]
I think this data is an array, but
console.log(typeof doc.orders);//object
console.log(doc.orders.length);//undefined
console.log(doc.orders[0].order);//error
console.log(Array.isArray(doc.orders));//false
I do not know how to delete null value of this data and how to change this data into an array?
By the way, I find a post in gist said that mongoose populate.match will return null value if it did not match the condition, is that true?
I make mistake that I define the schema the wrong way.
The wrong schema:
orders:{order: [{type: mongoose.Schema.Types.ObjectId, ref:'Order'}] }
The right way the define schema in array which you what to populate:
orders:{type:[{
order:{type: mongoose.Schema.Types.ObjectId, ref:'Order'}
}]}
After this, use populate.match will give you an legal array and your could do with it like normal array.

elasticsearch search text return full array issue

I am using mongoosastic for elasticsearch. and i done all setup and its working fine. but problem is result are not getting properly.
FILE:- mongoose and mongoosastic.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var medicineSchema = require('./search')
var mongoosastic = require("mongoosastic");
var UserProfileSchema = new Schema({
userId: String,
username: String,
address: String,
number: Number,
task: [{
name: {
type: String,
es_boost: 2.0 // or es_indexed:true
},
taskCode: String,
}]
});
UserProfileSchema.plugin(mongoosastic);
UserProfileSchema.plugin(mongoosastic, {
host: "localhost",
port: 9200,
// ,curlDebug: true
});
UserProfile = module.exports = mongoose.model('UserProfile', UserProfileSchema);
UserProfile.createMapping(function(err, mapping) {
if (err) {
console.log('error creating mapping (you can safely ignore this)');
console.log(err);
} else {
console.log('mapping created!');
console.log(mapping);
}
});
And my search Query:
var UserProfileSchema = require('../../app/models/user');
UserProfileSchema.search({
query_string: {
query: name
}
}, function(err, result) {
if (err) {
callback({
RESULT_CODE: '-1',
MESSAGE: 'System error'
});
} else {
callback({
RESULT_CODE: '1',
DATA: result
});
}
});
Now my problem is if task array has 3 object and when i search for task string i.e "abc" it will return full collection. with all task But i want only searched string object from task array. i.e name :abc object
......
"task" [{
name: 'abc',
taskCode: 123
},{
name: 'xyz',
taskCode: 123
},{
name: 'cdx',
taskCode: 123
}]
The good thing is that your task field is already of type nested in your schema, which is a pre-condition for achieving what you expect.
Now in order to achieve what you want you need to use inner_hits in your query.
UserProfileSchema.search({
"query": {
"nested": {
"path": "task",
"query": {
"match": {
"task.name": name
}
},
"inner_hits": {} <--- this does the magic
}
}
}, ...

Update $inc with Mongoose other behavior then MongoDB update

I try to update a document with mongoose and it fails. The query I can successful execute directly in Mongo is like:
db.orders.update(
{
orderId: 1014428,
'delivery.items.id': '5585d77c714a90fe0fc2fcb4'
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}
)
When I try to run the following update command with mongoose:
this.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
I see the following error:
{ [MongoError: cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})]
name: 'MongoError',
message: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})',
index: 0,
code: 16837,
errmsg: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})' }
The raw response from Mongo was { ok: 0, n: 0, nModified: 0 }
I tried so many things. Any advice on this?
As requested the schema:
var Order = new Schema({
orderId: Number,
orderDate: String,
customerName: String,
state: Number,
delivery: {
items: {type: Array, default: []},
state: { type: Number, default: 0 }
}
});
TL;DR: use your model Order instead of an instance this when doing more advanced queries:
Orders.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
Explanation:
Mapping differences between Model.update() and Document.update().
The using the model, then Model.update() will be used and
Model.update(conditions, doc, options, callback)
will be mapped to:
db.collection.update(query = conditions, update = doc, options)
When using an instance instead your calling Document.update() and
Document.update(doc, options, callback)
will be mapped to the following:
db.collection.update(query = {_id: _id}, update = doc, options)
Don't know if this helps, but in this question the O.P. had a similar issue with mongoose 3.6.15, and claimed it was solved in 3.8.22
EDIT: In the linked question, the O.P. had the following working on mongodb
db.orchards.update(
({"orchardId": ObjectId("5391c137722b051908000000")},
{"trees" : { $elemMatch: {"name":"apple"}}}),
{ $push: { "trees.$.fruits": ObjectId("54c542c9d900000000001234") }})
But this not working in mongoose:
orchards.update(
({"orchardId": ObjectId.fromString(orchard.id)},
{"trees" : {$elemMatch: {"name": "apple"}}}),
{$push: {"trees.$.fruits": ObjectId("54c542c9d900000000001234") }},function(err, data){ ...
In a comment, he said the issue was solved switching to mongoose 3.8.22

Resources