Related
{
"a": [
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
],
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
]
]
}
How to create the schema in the realm(React native) for this type of JSON object. I tried all possible ways but did not found any specific solution. Basically, it is a nested array where the second array does not have any specific key(I tried with key it works fine but I want to do it without adding key).
You can use something like:
const ParentSchema = {
name: "parent",
properties: {
key: "string",
values: "Value[]"
}
};
const ValueSchema = {
name: "Value",
embedded: true,
properties: {
_id: "string",
title: "string"
}
};
You can insert objects like:
realm.write(() => {
realm.create("Parent", { key: "a", values: [
{ _id: "57e55b64016c3551c025abc1", title: "Main Campus" },
{ _id: "5810e2e27064497f74ad4874", title: "Ahm Campus" }
]
});
});
Documentation: https://docs.mongodb.com/realm/node/data-model
As of now there is no way to insert direct value in Realm database without key so for now we need to modify data and then we can store in following schema.
const ParentSchema = {
name: "parent",
properties: {
a: "level[]"
}
};
const level = {
name: 'level',
properties: {
level: 'sites[]'
}
}
const sites = {
name: 'sites',
properties: {
sites: 'site[]'
}
}
const site = {
name: 'site',
properties: {
title: 'string?',
_id: 'string?',
version: 'int?',
}
}
Data modification need to done like following.
var a = {
level: []
}
data.a.map((Site, index) => {
const sites = []
Site.map((s) => { sites.push(s)})
a.level.push({sites})
})
I have a question about this JSON. How to get coordinates from here?
I try to use for(){} like code below but doesn't work.
item {
"type": "type1",
"features": [{
"type": "typeee1",
"geometry": {
"type": "Point",
"coordinates": [
-19.726330999999998,
41.360610000000001
]},
"properties": {
"id_strada": "1433",
"nome_strada": "test3",
} },
{
"type": "typeee2",
"geometry": {
"type": "Point",
"coordinates": [
19.726344999999998,
26.36063
] },
"properties": {
id_strada": "13",
"nome_strada": "test5",
} },
{
"type": "typeee3",
"geometry": {
"type": "Point",
"coordinates": [
19.726358999999999,
98.36065
] },
"properties": {
id_strada": "14",
"nome_strada": "test34",
} }, {
"type": "typeee5",
"geometry": {
"type": "Point",
"coordinates": [
19.726372999999999,
55.360669999999999
] },
"properties": {
id_strada": "14335",
"nome_strada": "test39",
} }],
"last_update": "15-08-2019 15:04:45"
}
function that call JSON is like below.
item: Item[];
this.ws.getitems().subscribe(
item => {
this.item = item;
console.log('this.item.length', this.item.length)
for (let i = 0; i < this.item.length; i++) {
}
}
);
this.item.length is undefined
My question is, how to get coordinates in here?
Can you ask me any idea please?
Thanks!
You don't have an array in an array in an array. You have an array in an object in an object in an array in an object.
interface Feature {
type: string;
geometry: {
type: string;
coordinates: [ number, number ];
};
properties: {
id_strada: string;
nome_strada: string;
};
}
interface Item {
type: string;
features: Feature[];
last_update: string;
}
const items$: Observable<Item> = this.ws.getItems();
const coordinates$: Observable<[number, number]> = items$.pipe(
switchMap((item: Item) => of(
...item.features.map((feature: Feature) => feature.geometry.coordinates)
)),
);
coordinates$.subscribe((coordinates: [number, number]) => console.log(coordinates));
It is really unclear exactly what your intention is here. Your Item object has multiple coordinates within it. Do you intend to link all of the coordinates, or just the first, or do you want to split them by feature? I've provided you a way to just have an unlinked stream of all coordinates you ever receive. You'll have to figure out what it is you want to do with that.
If you were already in item, coordinates are at item.geometry.coordinates
If your supplied json was x, you could get the first coordinates at x.features[0].geometry.coordinates.
You could find each set of coordinates with:
x.features.forEach(item => {
let coords = item.geometry.coordinates
// do something with coords
})
I need to modify a document inside an array that is inside another array.
I know MongoDB doesn't support multiple '$' to iterate on multiple arrays at the same time, but they introduced arrayFilters for that.
See: https://jira.mongodb.org/browse/SERVER-831
MongoDB's sample code:
db.coll.update({}, {$set: {“a.$[i].c.$[j].d”: 2}}, {arrayFilters: [{“i.b”: 0}, {“j.d”: 0}]})
Input: {a: [{b: 0, c: [{d: 0}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Output: {a: [{b: 0, c: [{d: 2}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Here's how the documents are set:
{
"_id" : ObjectId("5a05a8b7e0ce3444f8ec5bd7"),
"name" : "support",
"contactTypes" : {
"nonWorkingHours" : [],
"workingHours" : []
},
"workingDays" : [],
"people" : [
{
"enabled" : true,
"level" : "1",
"name" : "Someone",
"_id" : ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
"contacts" : [
{
"_id" : ObjectId("5a05a8dee0ce3444f8ec5bda"),
"retries" : "1",
"priority" : "1",
"type" : "email",
"data" : "some.email#email.com"
}
]
}
],
"__v" : 0
}
Here's the schema:
const ContactSchema = new Schema({
data: String,
type: String,
priority: String,
retries: String
});
const PersonSchema = new Schema({
name: String,
level: String,
priority: String,
enabled: Boolean,
contacts: [ContactSchema]
});
const GroupSchema = new Schema({
name: String,
people: [PersonSchema],
workingHours: { start: String, end: String },
workingDays: [Number],
contactTypes: { workingHours: [String], nonWorkingHours: [String] }
});
I need to update a contact. This is what I tried using arrayFilters:
Group.update(
{},
{'$set': {'people.$[i].contacts.$[j].data': 'new data'}},
{arrayFilters: [
{'i._id': mongoose.Types.ObjectId(req.params.personId)},
{'j._id': mongoose.Types.ObjectId(req.params.contactId)}]},
function(err, doc) {
if (err) {
res.status(500).send(err);
}
res.send(doc);
}
);
The document is never updated and I get this response:
{
"ok": 0,
"n": 0,
"nModified": 0
}
What am I doing wrong?
So the arrayFilters option with positional filtered $[<identifier>] does actually work properly with the development release series since MongoDB 3.5.12 and also in the current release candidates for the MongoDB 3.6 series, where this will actually be officially released. The only problem is of course is that the "drivers" in use have not actually caught up to this yet.
Re-iterating the same content I have already placed on Updating a Nested Array with MongoDB:
NOTE Somewhat ironically, since this is specified in the "options" argument for .update() and like methods, the syntax is generally compatible with all recent release driver versions.
However this is not true of the mongo shell, since the way the method is implemented there ( "ironically for backward compatibility" ) the arrayFilters argument is not recognized and removed by an internal method that parses the options in order to deliver "backward compatibility" with prior MongoDB server versions and a "legacy" .update() API call syntax.
So if you want to use the command in the mongo shell or other "shell based" products ( notably Robo 3T ) you need a latest version from either the development branch or production release as of 3.6 or greater.
All this means is that the current "driver" implementation of .update() actually "removes" the necessary arguments with the definition of arrayFilters. For NodeJS this will be addressed in the 3.x release series of the driver, and of course "mongoose" will then likely take some time after that release to implement it's own dependencies on the updated driver, which would then no longer "strip" such actions.
You can however still run this on a supported server instance, by dropping back to the basic "update command" syntax usage, since this bypassed the implemented driver method:
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = mongoose.Types.ObjectId;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const contactSchema = new Schema({
data: String,
type: String,
priority: String,
retries: String
});
const personSchema = new Schema({
name: String,
level: String,
priority: String,
enabled: Boolean,
contacts: [contactSchema]
});
const groupSchema = new Schema({
name: String,
people: [personSchema],
workingHours: { start: String, end: String },
workingDays: { type: [Number], default: undefined },
contactTypes: {
workingHours: { type: [String], default: undefined },
contactTypes: { type: [String], default: undefined }
}
});
const Group = mongoose.model('Group', groupSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clean data
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.remove() )
);
// Create sample
await Group.create({
name: "support",
people: [
{
"_id": ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "adifferent.email#example.com"
},
{
"_id": ObjectId("5a05a8dee0ce3444f8ec5bda"),
"retries": "1",
"priority": "1",
"type": "email",
"data": "some.email#example.com"
}
]
}
]
});
let result = await conn.db.command({
"update": Group.collection.name,
"updates": [
{
"q": {},
"u": { "$set": { "people.$[i].contacts.$[j].data": "new data" } },
"multi": true,
"arrayFilters": [
{ "i._id": ObjectId("5a05a8c3e0ce3444f8ec5bd8") },
{ "j._id": ObjectId("5a05a8dee0ce3444f8ec5bda") }
]
}
]
});
log(result);
let group = await Group.findOne();
log(group);
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Since that sends the "command" directly through to the server, we see the expected update does in fact take place:
Mongoose: groups.remove({}, {})
Mongoose: groups.insert({ name: 'support', _id: ObjectId("5a06557fb568aa0ad793c5e4"), people: [ { _id: ObjectId("5a05a8c3e0ce3444f8ec5bd8"), enabled: true, level: '1', name: 'Someone', contacts: [ { type: 'email', data: 'adifferent.email#example.com', _id: ObjectId("5a06557fb568aa0ad793c5e5") }, { _id: ObjectId("5a05a8dee0ce3444f8ec5bda"), retries: '1', priority: '1', type: 'email', data: 'some.email#example.com' } ] } ], __v: 0 })
{ n: 1,
nModified: 1,
opTime:
{ ts: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
t: 24 },
electionId: 7fffffff0000000000000018,
ok: 1,
operationTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
'$clusterTime':
{ clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
signature: { hash: [Object], keyId: 0 } } }
Mongoose: groups.findOne({}, { fields: {} })
{
"_id": "5a06557fb568aa0ad793c5e4",
"name": "support",
"__v": 0,
"people": [
{
"_id": "5a05a8c3e0ce3444f8ec5bd8",
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "adifferent.email#example.com",
"_id": "5a06557fb568aa0ad793c5e5"
},
{
"_id": "5a05a8dee0ce3444f8ec5bda",
"retries": "1",
"priority": "1",
"type": "email",
"data": "new data" // <-- updated here
}
]
}
]
}
So right "now"[1] the drivers available "off the shelf" don't actually implement .update() or it's other implementing counterparts in a way that is compatible with actually passing through the necessary arrayFilters argument. So if you are "playing with" a development series or release candiate server, then you really should be prepared to be working with the "bleeding edge" and unreleased drivers as well.
But you can actually do this as demonstrated in any driver, in the correct form where the command being issued is not going to be altered.
[1] As of writing on November 11th 2017 there is no "official" release of MongoDB or the supported drivers that actually implement this. Production usage should be based on official releases of the server and supported drivers only.
I had a similar use case. But my second level nested array doesn't have a key. While most examples out there showcase an example with arrays having a key like this:
{
"id": 1,
"items": [
{
"name": "Product 1",
"colors": ["yellow", "blue", "black"]
}
]
}
My use case is like this, without the key:
{
"colors": [
["yellow"],
["blue"],
["black"]
]
}
I managed to use the arrayfilters by ommiting the label of the first level of the array nest. Example document:
db.createCollection('ProductFlow')
db.ProductFlow.insertOne(
{
"steps": [
[
{
"actionType": "dispatch",
"payload": {
"vehicle": {
"name": "Livestock Truck",
"type": "road",
"thirdParty": true
}
}
},
{
"actionType": "dispatch",
"payload": {
"vehicle": {
"name": "Airplane",
"type": "air",
"thirdParty": true
}
}
}
],
[
{
"actionType": "store",
"payload": {
"company": "Company A",
"is_supplier": false
}
}
],
[
{
"actionType": "sell",
"payload": {
"reseller": "Company B",
"is_supplier": false
}
}
]
]
}
)
In my case, I want to:
Find all documents that have any steps with payload.vehicle.thirdParty=true and actionType=dispatch
Update the actions set payload.vehicle.thirdParty=true only for the actions that have actionType=dispatch.
My first approach was withour arrayfilters. But it would create the property payload.vehicle.thirdParty=true inside the steps with actionType store and sell.
The final query that updated the properties only inside the steps with actionType=dispatch:
Mongo Shell:
db.ProductFlow.updateMany(
{"steps": {"$elemMatch": {"$elemMatch": {"payload.vehicle.thirdParty": true, "actionType": "dispatch"}}}},
{"$set": {"steps.$[].$[i].payload.vehicle.thirdParty": false}},
{"arrayFilters": [ { "i.actionType": "dispatch" } ], multi: true}
)
PyMongo:
query = {
"steps": {"$elemMatch": {"$elemMatch": {"payload.vehicle.thirdParty": True, "actionType": "dispatch"}}}
}
update_statement = {
"$set": {
"steps.$[].$[i].payload.vehicle.thirdParty": False
}
}
array_filters = [
{ "i.actionType": "dispatch" }
]
NOTE that I'm omitting the label on the first array at the update statement steps.$[].$[i].payload.vehicle.thirdParty. Most examples out there will use both labels because their objects have a key for the array. I took me some time to figure that out.
i am trying to push array in document array my collection is
{
"_id": "58eed81af6f8e3788de703f9",
"first_name": "abc",
"vehicles": {
"exhibit": "18",
"title": "Motor Velicle Information for Donald French",
"details": [
{
"year": "",
"make_model": "",
"registered_owner": "",
"license_number": "",
"date_of_purchase": "",
"purchase_price": ""
}
]
}
}
so what i want is to push data in details for that i had try like this
Licensee.update({"_id":"58eed81af6f8e3788de703f9"},{
$push:{
"vehicles.details":data
}
},function(err,data){
if(!err)
{
console.log('data',data);
}
else
{
console.log('err',err);
}
});
and for this i create one schema i don't know is right or not
var licSchema = new SimpleSchema({
"_id":{
type:String,
label:"_id",
optional: false,
},
"vehicles.details.year": {
type: String,
label: "year",
optional: true,
},
"vehicles.details.make_model": {
type: String,
label: "make_model",
optional: true,
}
});
where is my fault please give me solution .
Error Uncaught Error: After filtering out keys not in the schema, your modifier is now empty
You can try this. AddToSet should be the right way.
const schema = new SimpleSchema({
"vehicles.details.$.year": {
type: String,
label: "year",
optional: true,
},
"vehicles.details.$.make_model": {
type: String,
label: "make_model",
optional: true,
}
});
Licensee.update({"_id":"58eed81af6f8e3788de703f9"},{
$addToSet:{
"vehicles.details": data
}
});
I have a very particular issue concerning querying over a boolean field and a string field which are nested to an array field. The index mapping is as follow:
indexes :string_field_1, type: 'string'
indexes :string_field_2, type: 'string'
indexes :boolean_field_1, type: 'boolean'
indexes :array_field_1 do
indexes :boolean_field_2, type: 'boolean'
indexes :string_field_3, type: 'string'
end
indexes :array_field_2 do
indexes :integer_field_1, type: 'integer'
end
indexes :array_field_3 do
indexes :integer_field_2, type: 'integer'
end
The document index also has many other fields which are not nested to the array field, but have to be included among the query fields.
I have tried an approach using filter and bool queries that is as follow:
"query":
{"bool":
{"must":
[
{"query_string":
{"query":"text which is being searched",
"fields":[
"string_field_1",
"string_field_2",
"array_field_1.string_field_3"
],
"fuzziness":"1","analyze_wildcard":true,"auto_generate_phrase_queries":false,"analyzer":"brazilian","default_operator":"AND"}
}
],
"filter":[
{"bool":
{"must":
[
{"bool":
{"should":
[
{"term":{"boolean_field_1":false}},
{"terms":{"array_field_2.integer_field_1":[x,z]}},
{"term":{"array_field_3.integer_field_2":y}}]}},
{"bool":
{"should":
[
{"term":{"array_field_1.boolean_field_2":true}},
{"terms":{"array_field_2.integer_field_1":[x,z]}},
{"term":{"array_field_3.integer_field_2":y}}]}},
]
}
}
]
}
}
]
}
}
The problem with this query is that it is returning a document which, in my opinion, doesn't have to be returned.
The document, in this case, is the bellow:
_source": {
"string_field_1": "text 1",
"string_field_2": "text 2",
"boolean_field_1": false,
"array_field_1": [
{
"boolean_field_2": true,
"string_field_3": "some text which is not being searched"
},
{
"boolean_field_2": true,
"string_field_3": "some text which is not being searched"
},
{
"boolean_field_2": false,
"string_field_3": "text which is being searched"
},
{
"boolean_field_2": true,
"string_field_3": "some text which is not being searched"
}
],
"array_field_2": [
{
"integer_field_1": A
}
],
"array_field_3": [
{
"integer_field_2": B
}
]
}
As you can notice, the third item of array_field_1 contains boolean_field_2: false and also the text which is being searched. But, according to my filter: clause, only the documents which array_field_1.boolean_field_2 is true have to be retrieved, unless array_field_2.integer_field_1: or array_field_3.integer_field_1 occurs, which is not true, according to my query part.
It seems elastic is not considering that the array_field_1[2] is the one that the boolean_field_2 is false.
How can I make my query so that this document isn't retrieved?
Thanks is advance,
Guilherme
That was my solution:
"query":{
"bool":{
"should":
[
{
"query_string":
{
"query":"text which is being searched",
"fields":
[
"string_field_1",
"string_field_2"
],
"fuzziness":"1","analyze_wildcard":true,"auto_generate_phrase_queries":false,"analyzer":"brazilian","default_operator":"AND"
}
},
{
bool: {
should:[
{
query:{
nested: {
path: 'array_field_1',
query: {
bool: {
must: [
{ match: { "array_field_1.string_field_3": "text which is being searched"} },
{term: {"array_field_1.boolean_field_2": true}}
]
}
}
}
}
},
{
bool:
{
must: [
{
query:{
nested: {
path: 'movimentos',
query: {
bool: {
must: [
{ match: { "array_field_1.string_field_3": "text which is being searched"} },
{term: {"array_field_1.boolean_field_2": false
]
}
}
}
}
},
{
query: {
bool: {
should: [
{"terms":{"array_field_2.integer_field_1":[x,z]}},
{"term":{"array_field_3.integer_field_2":y}}
]
}
}
}
]
}
}
]
}
}
]
}
}
Another approach consists of putting the array_field_1.string_field_3 query together with the bool query related to the boolean field:
"query":{
"bool":{
"should":
[
{
"query_string":
{
"query":"text which is being searched",
"fields":
[
"string_field_1",
"string_field_2"
],
"fuzziness":"1","analyze_wildcard":true,"auto_generate_phrase_queries":false,"analyzer":"brazilian","default_operator":"AND"
}
},
{
"bool":{
"must":
[
{
"query_string":
{
"query":"text which is being searched",
"fields":["array_field_1.string_field_3"],
"fuzziness":"1","analyze_wildcard":true,"auto_generate_phrase_queries":false,"analyzer":"brazilian","default_operator":"AND"
}
},
{
"bool":{
"should":
[
{"term":{"array_field_1.boolean_field_2":true}},
{"terms":{"array_field_2.integer_field_1":[x,z]}},
{"term":{"array_field_3.integer_field_2":y}}
]
}
}
]
}
}
],
"filter":
[
{
"bool":{
"should":
[
{"term":{"boolean_field_1":false}},
{"terms":{"array_field_2.integer_field_1":[x,z]}},
{"term":{"array_field_3.integer_field_2":y}}
]
}
}
]
}
}
This query also retrieves the document, unfortunately. I really do not know how to build this query properly.
The query above is organized as:
(X) OR (A AND (B OR C OR D))