How to perform ilike query in array of object jsonb column using sequelize postgres - postgresql

so i have this data
table name: items
slug name metadata
blue round [
{
"value": "sweet",
"type": "block",
}
]
and i want to do something like this
where: [{
[Op.or]: [
{ slug: { [Op.iLike]: `%${value}%` } },
{ name: { [Op.iLike]: `%${value}%` } },
{ 'metadata.value': { [Op.iLike]: `%${value}%`}},
],
}]
it executing
("items"."metadata"#>>'{value}') ILIKE '%sweet%')
no error but give me no result
thank you in advance

solved this using literal and like regex in raw SQL
literal(`"items"."metadata" ## '$.* like_regex "${value}" flag "i"' `),
so my query looks like this
where: [{
[Op.or]: [
{ slug: { [Op.iLike]: `%${value}%` } },
{ name: { [Op.iLike]: `%${value}%` } },
literal(`"items"."metadata" ## '$.* like_regex "${value}" flag "i"' `),
],
}]

Related

Search MongoDB autocomplete filtered

I want to search autocomplete on the following fields :contactfirstname, contactlastname and name
Also, want to filter based on userid(s) first then perform autocomplete search
Issue:
Without filter criteria, autocomplete is working fine
With filter criteria in compound query not working as getting empty array
Can anyone help please?
exports.userNameCitySearchAutocomplete = async function (req, res) {
try {
const { userNameCityQueryparam } = req.query;
console.log("search query param", userNameCityQueryparam);
const agg = [
{
$search: {
index: 'userNameCity',
'compound': {
"filter": [{
"text": {
"query": ["6271f2bb79cd80194c81f631"],
"path": "_id",
}
}],
"should": [
{
//search on user name
autocomplete: {
query: userNameCityQueryparam,
path: 'name',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
}},
//search on user city
{
autocomplete: {
query: userNameCityQueryparam,
path: 'city',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
,
//search on user contact first name
{
autocomplete: {
query: userNameCityQueryparam,
path: 'contactfirstname',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
,
//search on user contact last name
{
autocomplete: {
query: userNameCityQueryparam,
path: 'contactlastname',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
],
"minimumShouldMatch": 1
}
}
}
]
const response = await User.aggregate(agg);
return res.json(response);
// res.send(response);
} catch (error) {
console.log("autocomplete search error", error);
return res.json([]);
}
};
Index details in mongodb:
{
"mappings": {
"dynamic": false,
"fields": {
"_id": {
"type": "string"
},
"city": {
"type": "autocomplete"
},
"contactfirstname": {
"type": "autocomplete"
},
"contactlastname": {
"type": "autocomplete"
},
"name": {
"type": "autocomplete"
}
}
}
}
Image of collection in mongodb
image of empty array
for anyone looking for solution to this,
You can use the MQL where clause in your pipeline stage definition.
{
$match: {
email:"email#domain.com"
}
}
check here for an example

mongo push to array in aggregation

I have the following code:
const newArray = [];
companies.items.forEach(async (item) => {
if (item.parentCompanyID) {
newArray.push({
updateOne: {
filter: { id: item?.parentCompanyID },
update: [
{
$push: {
branches: {
id: item?.id,
name: item.companyName,
parentId: item?.parentCompanyID,
type: item.companyType,
active: item.isActive,
number: item.companyNumber,
newlyAdded: { $eq: [{ $type: '$newlyAdded' }, 'missing'] },
},
},
},
],
upsert: true,
},
});
} else {
newArray.push({
updateOne: {
filter: { id: item?.id },
update: [
{
$set: {
id: item?.id,
name: item.companyName,
parentId: item?.parentCompanyID,
type: item.companyType,
active: item.isActive,
number: item.companyNumber,
newlyAdded: { $eq: [{ $type: '$newlyAdded' }, 'missing'] },
},
},
],
upsert: true,
},
});
}
});
await Company.bulkWrite(newArray);
This will go through company.items and for each will add updateOne into newArray which will the goes to bulkWrite.
My problem lies with $push as this needs to be in aggregation pipeline, and when i add the brackets around update it will break with MongooseError: Invalid update pipeline operator: "$push"
Iam sure the script could be simplified but iam still fairly new to mongoDB. What i need is this to insert to Company if the item hasnt got parentCompanyID, if it does have than push to branches array for the relevant Company with id of parentCompanyID.
Sample data from company.items array:
{
id: 5,
name: "Sports"
parentCompanyID: null
},
{
id: 51,
name: "Football"
parentCompanyID: 5
}
And MongoDB for COmpany should look like this:
{
id: 5,
name: "Sports",
parentCompanyID: null,
branches: [{
id: 51,
name: "Football",
parentCompanyID: 5
}]
}
Hope this makes sense. ANy help would be appreciated. I could not find any similar issue and only one i came accross was to use $concatArrays but this wouldnt work either.
Thank you
EDIT:
as per #Takis_ answer thsi now sort of works. Only problem is when $concatArrays does it jobs its not pushing into array as expected from $push. this is the result as of now, insted of branches being one array it has nested arrays. if there are more branches it follows same patter and it could end up with many nested arrays rather than 1 array of objects. any ideas?
{
"id": 29683585,
"name": "123",
"parentId": null,
"newlyAdded": true,
"branches": [
[
null,
{
"id": 29693873,
"name": "245",
"parentId": 29683585
}
],
{
"id": 29695646,
"name": "789",
"parentId": 29683585
}
]
}
This has now been sorted. Thanks to Takis and his pointing to $concatArrays i was able to make this works.
Working code is below:
newArray.push({
updateOne: {
filter: { id: item?.parentCompanyID },
update: [
{
$set: {
branches: {
$concatArrays: [
{ $ifNull: ['$branches', []] },
[
{
id: item?.id,
name: item.companyName,
parentId: item?.parentCompanyID,
type: item.companyType,
active: item.isActive,
number: item.companyNumber,
newlyAdded: { $ne: ['$newlyAdded', null] },
},
],
],
},
},
},
],
upsert: true,
},
});

What is the mongoose schema of this json example?

I am working on a Node.js project with MongoDb Database .
I need the schema of this json example :
I am working on a Node.js project with MongoDb Database .
I need the schema of this json example
MongoDb document :
{
"container_number": "ddd",
"container_Date": "2/2/2018",
"scannedProductArray": {
"CCR": [
{
"ScannedDate": {
"$date": "2018-03-28T20:54:57.663Z"
},
"productNumber": "4656874974",
"productType": "CCR"
},
{
"ScannedDate": {
"$date": "2018-03-28T20:55:23.698Z"
},
"productNumber": "4656874974",
"productType": "CCR"
}
],
"CCH": [
{
"ScannedDate": {
"$date": "2018-03-28T21:25:16.202Z"
},
"productNumber": "4656874974",
"productType": "CCR"
},
{
"ScannedDate": {
"$date": "2018-03-28T21:26:08.696Z"
},
"productNumber": "4656874974",
"productType": "CCR"
}
]
}
}
container_number: String,
container_Date: String,
scannedProductArray:{CCR:[ScannedDate: {
date:type:Date,default:Date.now
},
"productNumber:Number,
"productType": "String"],CCH[:[ScannedDate: {
date:type:Date,default:Date.now
},
"productNumber:Number,
"productType": "String"]}
May be this one helps you.
I'd like to define schemas like this:
const Product = {
ScannedDate: {
type: Object,
},
productNumber: {
type: String,
},
productType: {
type: String,
default: 'CCR',
}
};
const Item = {
itemName: {
type: [Product],
},
};
const Container = {
container_number: {
type: String,
},
container_Date: {
type: String
},
scannedProductArray: {
type: Object, // Item
}
};
If the CCR/CCH fields are dynamic, I can just use type: Object rather than a certain structure. And I validate these array items by myself instead of mongoose.

Update's request for mongodb [duplicate]

I have a document structure that is deeply nested, like this:
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{ level: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{ level: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
I'm trying to update the collection to insert a new config, that looks like this:
newdata = {
config: "Custom 1",
variables: [{ x: 111, y:2222, z:3333}]
}
I'm trying something like this in mongo (in Python):
db.myCollection.update({"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.$.configs.$": newData}}
)
I'm getting "Cannot apply the positional operator without a corresponding query field containing an array" error though. What is the proper way to do this in mongo? This is mongo v2.4.1.
Unfortunately, you can't use the $ operator more than once per key, so you have to use numeric values for the rest. As in:
db.myCollection.update({
"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.0.configs.0": newData}}
)
MongoDB's support for updating nested arrays is poor. So you're best off avoiding their use if you need to update the data frequently, and consider using multiple collections instead.
One possibility: make forecasts its own collection, and assuming you have a fixed set of level values, make level an object instead of an array:
{
_id: 123,
parentId: 1,
name: "Forecast 1",
levels: {
proven: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
likely: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
}
}
Then you can update it using:
db.myCollection.update({
_id: 123,
'levels.proven.configs.config': 'Custom 1'
},
{ $set: { 'levels.proven.configs.$': newData }}
)
Managed to solve it with using mongoose:
All you need to know is the '_id's of all of the sub-document in the chain (mongoose automatically create '_id' for each sub-document).
for example -
SchemaName.findById(_id, function (e, data) {
if (e) console.log(e);
data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
// or if you want to change more then one field -
//=> var t = data.sub1.id(_id1).sub2.id(_id2);
//=> t.field = req.body.something;
data.save();
});
More about the sub-document _id method in mongoose documentation.
explanation:_id is for the SchemaName, _id1 for sub1 and _id2 for sub2 - you can keep chaining like that.
*You don't have to use findById method, but it's seem to me the most convenient as you need to know the rest of the '_id's anyway.
MongoDB has introduced ArrayFilters to tackle this issue in Version 3.5.2 and later.
New in version 3.6.
Starting in MongoDB 3.6, when updating an array field, you can specify
arrayFilters that determine which array elements to update.
[https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]
Let's say the Schema design as follows :
var ProfileSchema = new Schema({
name: String,
albums: [{
tour_name: String,
images: [{
title: String,
image: String
}]
}]
});
And Document created looks like this :
{
"_id": "1",
"albums": [{
"images": [
{
"title": "t1",
"url": "url1"
},
{
"title": "t2",
"url": "url2"
}
],
"tour_name": "london-trip"
},
{
"images": [.........]:
}]
}
Say I want to update the "url" of an image.
Given - "document id", "tour_name" and "title"
For this the update query :
Profiles.update({_id : req.body.id},
{
$set: {
'albums.$[i].images.$[j].title': req.body.new_name
}
},
{
arrayFilters: [
{
"i.tour_name": req.body.tour_name, "j.image": req.body.new_name // tour_name - current tour name, new_name - new tour name
}]
})
.then(function (resp) {
console.log(resp)
res.json({status: 'success', resp});
}).catch(function (err) {
console.log(err);
res.status(500).json('Failed');
})
This is a very OLD bug in MongoDB
https://jira.mongodb.org/browse/SERVER-831
I was facing same kind of problem today, and after lot of exploring on google/stackoverflow/github, I figured arrayFilters are the best solution to this problem. Which would work with mongo 3.6 and above.
This link finally saved my day: https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html
const OrganizationInformationSchema = mongoose.Schema({
user: {
_id: String,
name: String
},
organizations: [{
name: {
type: String,
unique: true,
sparse: true
},
rosters: [{
name: {
type: String
},
designation: {
type: String
}
}]
}]
}, {
timestamps: true
});
And using mongoose in express, updating the name of roster of given id.
const mongoose = require('mongoose');
const ControllerModel = require('../models/organizations.model.js');
module.exports = {
// Find one record from database and update.
findOneRosterAndUpdate: (req, res, next) => {
ControllerModel.updateOne({}, {
$set: {
"organizations.$[].rosters.$[i].name": req.body.name
}
}, {
arrayFilters: [
{ "i._id": mongoose.Types.ObjectId(req.params.id) }
]
}).then(response => {
res.send(response);
}).catch(err => {
res.status(500).send({
message: "Failed! record cannot be updated.",
err
});
});
}
}
It's fixed.
https://jira.mongodb.org/browse/SERVER-831
But this feature is available starting with the MongoDB 3.5.12 development version.
Note: This question asked on Aug 11 2013 and it's resolved on Aug 11 2017
Given how MongoDB doesn't appear to provide a good mechanism for this, I find it prudent to use mongoose to simply extract the element from the mongo collection using .findOne(...), run a for-loop search on its relevant subelements (seeking by say ObjectID), modify that JSON, then do Schema.markModified('your.subdocument'); Schema.save(); It's probably not efficient, but it is very simple and works fine.
I searched about this for about 5 hours and finally found the best and easiest solution:
HOW TO UPDATE NESTED SUB-DOCUMENTS IN MONGO DB
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{
levelid:1221
levelname: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{
levelid:1221
levelname: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]}
Query:
db.weather.updateOne({
"_id": ObjectId("1"), //this is level O select
"forecasts": {
"$elemMatch": {
"forecast_id": ObjectId("123"), //this is level one select
"levels.levelid": ObjectId("1221") // this is level to select
}
}
},
{
"$set": {
"forecasts.$[outer].levels.$[inner].levelname": "New proven",
}
},
{
"arrayFilters": [
{ "outer.forecast_id": ObjectId("123") },
{ "inner.levelid": ObjectId("1221") }
]
}).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
Sharing my lessons learned. I faced the same requirement recently where i need to update a nested array item.
My structure is as follows
{
"main": {
"id": "ID_001",
"name": "Fred flinstone Inc"
},
"types": [
{
"typeId": "TYPE1",
"locations": [
{
"name": "Sydney",
"units": [
{
"unitId": "PHG_BTG1"
}
]
},
{
"name": "Brisbane",
"units": [
{
"unitId": "PHG_KTN1"
},
{
"unitId": "PHG_KTN2"
}
]
}
]
}
]
}
My requirement is to add some fields in a specific units[].
My solution is first to find the index of the nested array item (say foundUnitIdx)
The two techniques I used are
use the $set keyword
specify the dynamic field in $set using the [] syntax
query = {
"locations.units.unitId": "PHG_KTN2"
};
var updateItem = {
$set: {
["locations.$.units."+ foundUnitIdx]: unitItem
}
};
var result = collection.update(
query,
updateItem,
{
upsert: true
}
);
Hope this helps others. :)
EASY SOLUTION FOR Mongodb 3.2+
https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
I had a similar situation and solved it like this. I was using mongoose, but it should still work in vanilla MongoDB. Hope it's useful to someone.
const MyModel = require('./model.js')
const query = {id: 1}
// First get the doc
MyModel.findOne(query, (error, doc) => {
// Do some mutations
doc.foo.bar.etc = 'some new value'
// Pass in the mutated doc and replace
MyModel.replaceOne(query, doc, (error, newDoc) => {
console.log('It worked!')
})
}
Depending on your use case, you might be able to skip the initial findOne()
Okkk.we can update our nested subdocument in mongodb.this is our schema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
solution for this schema
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{"post.$.comment.0.detail.time":"aajtk"}},
function(err,data){
//data is updated
})

Mongodb update deeply nested subdocument

I have a document structure that is deeply nested, like this:
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{ level: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{ level: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
I'm trying to update the collection to insert a new config, that looks like this:
newdata = {
config: "Custom 1",
variables: [{ x: 111, y:2222, z:3333}]
}
I'm trying something like this in mongo (in Python):
db.myCollection.update({"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.$.configs.$": newData}}
)
I'm getting "Cannot apply the positional operator without a corresponding query field containing an array" error though. What is the proper way to do this in mongo? This is mongo v2.4.1.
Unfortunately, you can't use the $ operator more than once per key, so you have to use numeric values for the rest. As in:
db.myCollection.update({
"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.0.configs.0": newData}}
)
MongoDB's support for updating nested arrays is poor. So you're best off avoiding their use if you need to update the data frequently, and consider using multiple collections instead.
One possibility: make forecasts its own collection, and assuming you have a fixed set of level values, make level an object instead of an array:
{
_id: 123,
parentId: 1,
name: "Forecast 1",
levels: {
proven: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
likely: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
}
}
Then you can update it using:
db.myCollection.update({
_id: 123,
'levels.proven.configs.config': 'Custom 1'
},
{ $set: { 'levels.proven.configs.$': newData }}
)
Managed to solve it with using mongoose:
All you need to know is the '_id's of all of the sub-document in the chain (mongoose automatically create '_id' for each sub-document).
for example -
SchemaName.findById(_id, function (e, data) {
if (e) console.log(e);
data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
// or if you want to change more then one field -
//=> var t = data.sub1.id(_id1).sub2.id(_id2);
//=> t.field = req.body.something;
data.save();
});
More about the sub-document _id method in mongoose documentation.
explanation:_id is for the SchemaName, _id1 for sub1 and _id2 for sub2 - you can keep chaining like that.
*You don't have to use findById method, but it's seem to me the most convenient as you need to know the rest of the '_id's anyway.
MongoDB has introduced ArrayFilters to tackle this issue in Version 3.5.2 and later.
New in version 3.6.
Starting in MongoDB 3.6, when updating an array field, you can specify
arrayFilters that determine which array elements to update.
[https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]
Let's say the Schema design as follows :
var ProfileSchema = new Schema({
name: String,
albums: [{
tour_name: String,
images: [{
title: String,
image: String
}]
}]
});
And Document created looks like this :
{
"_id": "1",
"albums": [{
"images": [
{
"title": "t1",
"url": "url1"
},
{
"title": "t2",
"url": "url2"
}
],
"tour_name": "london-trip"
},
{
"images": [.........]:
}]
}
Say I want to update the "url" of an image.
Given - "document id", "tour_name" and "title"
For this the update query :
Profiles.update({_id : req.body.id},
{
$set: {
'albums.$[i].images.$[j].title': req.body.new_name
}
},
{
arrayFilters: [
{
"i.tour_name": req.body.tour_name, "j.image": req.body.new_name // tour_name - current tour name, new_name - new tour name
}]
})
.then(function (resp) {
console.log(resp)
res.json({status: 'success', resp});
}).catch(function (err) {
console.log(err);
res.status(500).json('Failed');
})
This is a very OLD bug in MongoDB
https://jira.mongodb.org/browse/SERVER-831
I was facing same kind of problem today, and after lot of exploring on google/stackoverflow/github, I figured arrayFilters are the best solution to this problem. Which would work with mongo 3.6 and above.
This link finally saved my day: https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html
const OrganizationInformationSchema = mongoose.Schema({
user: {
_id: String,
name: String
},
organizations: [{
name: {
type: String,
unique: true,
sparse: true
},
rosters: [{
name: {
type: String
},
designation: {
type: String
}
}]
}]
}, {
timestamps: true
});
And using mongoose in express, updating the name of roster of given id.
const mongoose = require('mongoose');
const ControllerModel = require('../models/organizations.model.js');
module.exports = {
// Find one record from database and update.
findOneRosterAndUpdate: (req, res, next) => {
ControllerModel.updateOne({}, {
$set: {
"organizations.$[].rosters.$[i].name": req.body.name
}
}, {
arrayFilters: [
{ "i._id": mongoose.Types.ObjectId(req.params.id) }
]
}).then(response => {
res.send(response);
}).catch(err => {
res.status(500).send({
message: "Failed! record cannot be updated.",
err
});
});
}
}
It's fixed.
https://jira.mongodb.org/browse/SERVER-831
But this feature is available starting with the MongoDB 3.5.12 development version.
Note: This question asked on Aug 11 2013 and it's resolved on Aug 11 2017
Given how MongoDB doesn't appear to provide a good mechanism for this, I find it prudent to use mongoose to simply extract the element from the mongo collection using .findOne(...), run a for-loop search on its relevant subelements (seeking by say ObjectID), modify that JSON, then do Schema.markModified('your.subdocument'); Schema.save(); It's probably not efficient, but it is very simple and works fine.
I searched about this for about 5 hours and finally found the best and easiest solution:
HOW TO UPDATE NESTED SUB-DOCUMENTS IN MONGO DB
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{
levelid:1221
levelname: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{
levelid:1221
levelname: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]}
Query:
db.weather.updateOne({
"_id": ObjectId("1"), //this is level O select
"forecasts": {
"$elemMatch": {
"forecast_id": ObjectId("123"), //this is level one select
"levels.levelid": ObjectId("1221") // this is level to select
}
}
},
{
"$set": {
"forecasts.$[outer].levels.$[inner].levelname": "New proven",
}
},
{
"arrayFilters": [
{ "outer.forecast_id": ObjectId("123") },
{ "inner.levelid": ObjectId("1221") }
]
}).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
Sharing my lessons learned. I faced the same requirement recently where i need to update a nested array item.
My structure is as follows
{
"main": {
"id": "ID_001",
"name": "Fred flinstone Inc"
},
"types": [
{
"typeId": "TYPE1",
"locations": [
{
"name": "Sydney",
"units": [
{
"unitId": "PHG_BTG1"
}
]
},
{
"name": "Brisbane",
"units": [
{
"unitId": "PHG_KTN1"
},
{
"unitId": "PHG_KTN2"
}
]
}
]
}
]
}
My requirement is to add some fields in a specific units[].
My solution is first to find the index of the nested array item (say foundUnitIdx)
The two techniques I used are
use the $set keyword
specify the dynamic field in $set using the [] syntax
query = {
"locations.units.unitId": "PHG_KTN2"
};
var updateItem = {
$set: {
["locations.$.units."+ foundUnitIdx]: unitItem
}
};
var result = collection.update(
query,
updateItem,
{
upsert: true
}
);
Hope this helps others. :)
EASY SOLUTION FOR Mongodb 3.2+
https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
I had a similar situation and solved it like this. I was using mongoose, but it should still work in vanilla MongoDB. Hope it's useful to someone.
const MyModel = require('./model.js')
const query = {id: 1}
// First get the doc
MyModel.findOne(query, (error, doc) => {
// Do some mutations
doc.foo.bar.etc = 'some new value'
// Pass in the mutated doc and replace
MyModel.replaceOne(query, doc, (error, newDoc) => {
console.log('It worked!')
})
}
Depending on your use case, you might be able to skip the initial findOne()
Okkk.we can update our nested subdocument in mongodb.this is our schema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
solution for this schema
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{"post.$.comment.0.detail.time":"aajtk"}},
function(err,data){
//data is updated
})